Browse Source

GDrive integration WIP

Signed-off-by: Felix Paul Kühne <fkuehne@videolan.org>
Carola Nitz 11 years ago
parent
commit
4b4ed8b344

+ 3 - 0
AspenProject.xcworkspace/contents.xcworkspacedata

@@ -5,6 +5,9 @@
       location = "group:VLC for iOS.xcodeproj">
    </FileRef>
    <FileRef
+      location = "group:ImportedSources/GDrive/GTL.xcodeproj">
+   </FileRef>
+   <FileRef
       location = "group:ImportedSources/MediaLibraryKit/MediaLibraryKit.xcodeproj">
    </FileRef>
    <FileRef

+ 2 - 0
AspenProject/VLCAppDelegate.h

@@ -9,6 +9,7 @@
 //
 
 #import "VLCDropboxTableViewController.h"
+#import "VLCGoogleDriveTableViewController.h"
 #import "VLCHTTPUploaderController.h"
 #import "GHRevealViewController.h"
 #import "VLCMenuTableViewController.h"
@@ -27,6 +28,7 @@
 
 @property (nonatomic, readonly) VLCPlaylistViewController *playlistViewController;
 @property (nonatomic, readonly) VLCDropboxTableViewController *dropboxTableViewController;
+@property (nonatomic, readonly) VLCGoogleDriveTableViewController *googleDriveTableViewController;
 @property (nonatomic, readonly) VLCDownloadViewController *downloadViewController;
 
 @property (nonatomic, strong) UIWindow *window;

+ 11 - 0
AspenProject/VLCAppDelegate.m

@@ -25,6 +25,7 @@
 @interface VLCAppDelegate () <PAPasscodeViewControllerDelegate, VLCMediaFileDiscovererDelegate> {
     PAPasscodeViewController *_passcodeLockController;
     VLCDropboxTableViewController *_dropboxTableViewController;
+    VLCGoogleDriveTableViewController *_googleDriveTableViewController;
     VLCDownloadViewController *_downloadViewController;
     int _idleCounter;
     VLCMovieViewController *_movieViewController;
@@ -175,6 +176,16 @@
     return _dropboxTableViewController;
 }
 
+- (VLCGoogleDriveTableViewController *)googleDriveTableViewController
+{
+    if (_googleDriveTableViewController == nil) {
+        _googleDriveTableViewController = [[VLCGoogleDriveTableViewController alloc] initWithNibName:nil bundle:nil];
+    }
+
+    return _googleDriveTableViewController;
+}
+
+
 - (VLCDownloadViewController *)downloadViewController
 {
     if (_downloadViewController == nil) {

+ 15 - 0
AspenProject/VLCGoogleDriveConstants.h

@@ -0,0 +1,15 @@
+//
+//  VLCGoogleDriveConstants.h
+//  VLC for iOS
+//
+//  Created by Carola Nitz on 21.09.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+#define kVLCGoogleDriveClientID @"775640710334.apps.googleusercontent.com"
+#warning Google Drive app secret missing, login will fail
+#define kVLCGoogleDriveClientSecret @""
+//#define kVLCGoogleDriveAppKey @"a60fc6qj9zdg7bw"
+#warning Google Drive app private key missing, login will fail
+#define kVLCGoogleDrivePrivateKey @""

+ 36 - 0
AspenProject/VLCGoogleDriveController.h

@@ -0,0 +1,36 @@
+//
+//  VLCGoogleDriveController.h
+//  VLC for iOS
+//
+//  Created by Carola Nitz on 21.09.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+#import "GTLDrive.h"
+
+@protocol VLCGoogleDriveController
+@required
+- (void)mediaListUpdated;
+
+@optional
+- (void)operationWithProgressInformationStarted;
+- (void)currentProgressInformation:(float)progress;
+- (void)operationWithProgressInformationStopped;
+- (void)numberOfFilesWaitingToBeDownloadedChanged;
+@end
+
+@interface VLCGoogleDriveController : NSObject
+
+@property (nonatomic, retain) id delegate;
+@property (nonatomic, readonly) NSArray *currentListFiles;
+@property (nonatomic, readwrite) BOOL isAuthorized;
+@property (nonatomic, readonly) NSInteger numberOfFilesWaitingToBeDownloaded;
+@property (nonatomic, retain) GTLServiceDrive *driveService;
+
+- (void)startSession;
+- (void)logout;
+- (void)requestDirectoryListingAtPath:(NSString *)path;
+//- (void)downloadFileToDocumentFolder:(DBMetadata *)file;
+
+@end

+ 253 - 0
AspenProject/VLCGoogleDriveController.m

@@ -0,0 +1,253 @@
+//
+//  VLCGoogleDriveController.m
+//  VLC for iOS
+//
+//  Created by Carola Nitz on 21.09.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+
+#import "VLCGoogleDriveController.h"
+#import "NSString+SupportedMedia.h"
+#import "VLCAppDelegate.h"
+#import "HTTPMessage.h"
+#import "VLCGoogleDriveConstants.h"
+
+static NSString *const kKeychainItemName = @"Google Drive Quickstart #2";
+
+@interface VLCGoogleDriveController ()
+{
+    GTLDriveFileList *_fileList;
+    NSError *_fileListFetchError;
+    GTLServiceTicket *_fileListTicket;
+    NSArray *_currentFileList;
+
+    NSMutableArray *_listOfGoogleDriveFilesToDownload;
+    BOOL _downloadInProgress;
+
+    NSInteger _outstandingNetworkRequests;
+}
+
+@end
+
+@implementation VLCGoogleDriveController
+
+#pragma mark - session handling
+
+- (void)startSession
+{
+    self.driveService = [[GTLServiceDrive alloc] init];
+    self.driveService.authorizer = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName clientID:kVLCGoogleDriveClientID clientSecret:kVLCGoogleDriveClientSecret];
+}
+
+- (void)logout
+{
+}
+
+- (BOOL)isAuthorized
+{
+    return [((GTMOAuth2Authentication *)self.driveService.authorizer) canAuthorize];;
+}
+
+- (void)showAlert:(NSString *)title message:(NSString *)message
+{
+    UIAlertView *alert;
+    alert = [[UIAlertView alloc] initWithTitle: title
+                                       message: message
+                                      delegate: nil
+                             cancelButtonTitle: @"OK"
+                             otherButtonTitles: nil];
+    [alert show];
+}
+
+#pragma mark - file management
+- (void)requestDirectoryListingAtPath:(NSString *)path
+{
+    if (self.isAuthorized)
+        [self listFiles];
+}
+
+- (void)downloadFileToDocumentFolder:(DBMetadata *)file
+{
+    if (!file.isDirectory) {
+        if (!_listOfGoogleDriveFilesToDownload)
+            _listOfGoogleDriveFilesToDownload = [[NSMutableArray alloc] init];
+        [_listOfGoogleDriveFilesToDownload addObject:file];
+
+        if ([self.delegate respondsToSelector:@selector(numberOfFilesWaitingToBeDownloadedChanged)])
+            [self.delegate numberOfFilesWaitingToBeDownloadedChanged];
+
+        [self _triggerNextDownload];
+    }
+}
+
+- (void)listFiles
+{
+    _fileList = nil;
+    _fileListFetchError = nil;
+
+    GTLServiceDrive *service = self.driveService;
+
+    GTLQueryDrive *query = [GTLQueryDrive queryForFilesList];
+
+    // maxResults specifies the number of results per page.  Since we earlier
+    // specified shouldFetchNextPages=YES, all results should be fetched,
+    // though specifying a larger maxResults will reduce the number of fetches
+    // needed to retrieve all pages.
+    query.maxResults = 150;
+
+    // The Drive API's file entries are chock full of data that the app may not
+    // care about. Specifying the fields we want here reduces the network
+    // bandwidth and memory needed for the collection.
+    //
+    // For example, leave query.fields as nil during development.
+    // When ready to test and optimize your app, specify just the fields needed.
+    // For example, this sample app might use
+    //
+    // query.fields = @"kind,etag,items(id,downloadUrl,editable,etag,exportLinks,kind,labels,originalFilename,title)";
+    //TODO:specify query.fields 
+
+    _fileListTicket = [service executeQuery:query
+                          completionHandler:^(GTLServiceTicket *ticket,
+                                              GTLDriveFileList *fileList,
+                                              NSError *error) {
+                              // Callback
+                              _fileList = fileList;
+                              
+                              _fileListFetchError = error;
+                              _fileListTicket = nil;
+                              [self listOfGoodFiles];
+                          }];
+
+  //  [self updateUI];
+}
+
+- (void)_triggerNextDownload
+{
+    if (_listOfGoogleDriveFilesToDownload.count > 0 && !_downloadInProgress) {
+        [self _reallyDownloadFileToDocumentFolder:_listOfGoogleDriveFilesToDownload[0]];
+        [_listOfGoogleDriveFilesToDownload removeObjectAtIndex:0];
+
+        if ([self.delegate respondsToSelector:@selector(numberOfFilesWaitingToBeDownloadedChanged)])
+            [self.delegate numberOfFilesWaitingToBeDownloadedChanged];
+    }
+}
+
+- (void)_reallyDownloadFileToDocumentFolder:(DBMetadata *)file
+{
+    NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+    NSString *filePath = [searchPaths[0] stringByAppendingFormat:@"/%@", file.filename];
+
+    //[[self restClient] loadFile:file.path intoPath:filePath];
+
+    if ([self.delegate respondsToSelector:@selector(operationWithProgressInformationStarted)])
+        [self.delegate operationWithProgressInformationStarted];
+
+    _downloadInProgress = YES;
+}
+
+#pragma mark - restClient delegate
+- (BOOL)_supportedFileExtension:(NSString *)filename
+{
+    if ([filename isSupportedMediaFormat] || [filename isSupportedAudioMediaFormat] || [filename isSupportedSubtitleFormat])
+        return YES;
+
+    return NO;
+}
+
+- (void)listOfGoodFiles
+{
+    NSMutableArray *listOfGoodFilesAndFolders = [[NSMutableArray alloc] init];
+    
+    for (GTLDriveFile *driveFile in _fileList.items)
+    {
+        BOOL isDirectory = [driveFile.mimeType isEqualToString:@"application/vnd.google-apps.folder"];
+        if (isDirectory || [self _supportedFileExtension:driveFile.fileExtension]) {
+             [listOfGoodFilesAndFolders addObject:driveFile];
+        }
+    }
+
+    _currentFileList = [NSArray arrayWithArray:listOfGoodFilesAndFolders];
+
+    APLog(@"found filtered metadata for %i files", _currentFileList.count);
+    if ([self.delegate respondsToSelector:@selector(mediaListUpdated)])
+        [self.delegate mediaListUpdated];
+}
+
+//- (void)restClient:(DBRestClient *)client loadMetadataFailedWithError:(NSError *)error
+//{
+//    APLog(@"DBMetadata download failed with error %i", error.code);
+//}
+//
+//- (void)restClient:(DBRestClient*)client loadedFile:(NSString*)localPath
+//{
+//    /* update library now that we got a file */
+//    VLCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
+//    [appDelegate updateMediaList];
+//
+//    if ([self.delegate respondsToSelector:@selector(operationWithProgressInformationStopped)])
+//        [self.delegate operationWithProgressInformationStopped];
+//    _downloadInProgress = NO;
+//
+//    [self _triggerNextDownload];
+//}
+//
+//- (void)restClient:(DBRestClient*)client loadFileFailedWithError:(NSError*)error
+//{
+//    APLog(@"DBFile download failed with error %i", error.code);
+//    if ([self.delegate respondsToSelector:@selector(operationWithProgressInformationStopped)])
+//        [self.delegate operationWithProgressInformationStopped];
+//    _downloadInProgress = NO;
+//
+//    [self _triggerNextDownload];
+//}
+//
+//- (void)restClient:(DBRestClient*)client loadProgress:(CGFloat)progress forFile:(NSString*)destPath
+//{
+//    if ([self.delegate respondsToSelector:@selector(currentProgressInformation:)])
+//        [self.delegate currentProgressInformation:progress];
+//}
+//
+//#pragma mark - DBSession delegate
+//
+//- (void)sessionDidReceiveAuthorizationFailure:(DBSession *)session userId:(NSString *)userId
+//{
+//    APLog(@"DriveSession received authorization failure with user ID %@", userId);
+//}
+//
+//#pragma mark - DBNetworkRequest delegate
+//- (void)networkRequestStarted
+//{
+//    _outstandingNetworkRequests++;
+//    if (_outstandingNetworkRequests == 1) {
+//        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
+//        [(VLCAppDelegate*)[UIApplication sharedApplication].delegate disableIdleTimer];
+//    }
+//}
+
+- (void)networkRequestStopped
+{
+    _outstandingNetworkRequests--;
+    if (_outstandingNetworkRequests == 0) {
+        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
+        [(VLCAppDelegate*)[UIApplication sharedApplication].delegate activateIdleTimer];
+    }
+}
+
+#pragma mark - VLC internal communication and delegate
+
+- (NSArray *)currentListFiles
+{
+    return _currentFileList;
+}
+
+- (NSInteger)numberOfFilesWaitingToBeDownloaded
+{
+    if (_listOfGoogleDriveFilesToDownload)
+        return _listOfGoogleDriveFilesToDownload.count;
+
+    return 0;
+}
+
+@end

+ 25 - 0
AspenProject/VLCGoogleDriveTableViewCell.h

@@ -0,0 +1,25 @@
+//
+//  VLCDropboxTableViewCell.h
+//  VLC for iOS
+//
+//  Created by Carola Nitz on 21.09.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+
+//#import <DropboxSDK/DropboxSDK.h>
+
+@interface VLCGoogleDriveTableViewCell : UITableViewCell
+
+@property (nonatomic, strong) IBOutlet UILabel *titleLabel;
+@property (nonatomic, strong) IBOutlet UILabel *folderTitleLabel;
+@property (nonatomic, strong) IBOutlet UILabel *subtitleLabel;
+@property (nonatomic, strong) IBOutlet UIImageView *thumbnailView;
+
+//@property (nonatomic, retain) DBMetadata *fileMetadata;
+
++ (VLCGoogleDriveTableViewCell *)cellWithReuseIdentifier:(NSString *)ident;
++ (CGFloat)heightOfCell;
+
+@end

+ 38 - 0
AspenProject/VLCGoogleDriveTableViewCell.m

@@ -0,0 +1,38 @@
+//
+//  VLCGoogleDriveTableViewCell.m
+//  VLC for iOS
+//
+//  Created by Felix Paul Kühne on 24.05.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+
+#import "VLCGoogleDriveTableViewCell.h"
+
+@implementation VLCGoogleDriveTableViewCell
+
++ (VLCGoogleDriveTableViewCell *)cellWithReuseIdentifier:(NSString *)ident
+{
+    NSArray *nibContentArray = [[NSBundle mainBundle] loadNibNamed:@"VLCGoogleDriveTableViewCell" owner:nil options:nil];
+    NSAssert([nibContentArray count] == 1, @"meh");
+    NSAssert([[nibContentArray lastObject] isKindOfClass:[VLCGoogleDriveTableViewCell class]], @"meh meh");
+    VLCGoogleDriveTableViewCell *cell = (VLCGoogleDriveTableViewCell *)[nibContentArray lastObject];
+
+    return cell;
+}
+
+- (void)_updatedDisplayedInformation
+{
+    [self setNeedsDisplay];
+}
+
++ (CGFloat)heightOfCell
+{
+    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
+        return 80.;
+
+    return 48.;
+}
+
+@end

+ 25 - 0
AspenProject/VLCGoogleDriveTableViewController.h

@@ -0,0 +1,25 @@
+//
+//  VLCGoogleDriveTableViewController.h
+//  VLC for iOS
+//
+//  Created by Carola Nitz on 21.09.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+
+#import "VLCGoogleDriveController.h"
+#import "GTMOAuth2ViewControllerTouch.h"
+
+@interface VLCGoogleDriveTableViewController : UIViewController <VLCGoogleDriveController>
+
+@property (nonatomic, strong) IBOutlet UITableView *tableView;
+@property (nonatomic, strong) IBOutlet UIView *loginToGoogleDriveView;
+@property (nonatomic, strong) IBOutlet UIButton *loginToGoogleDriveButton;
+
+
+- (IBAction)loginToGoogleDriveAction:(id)sender;
+- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)authResult error:(NSError *)error;
+- (void)updateViewAfterSessionChange;
+
+@end

+ 299 - 0
AspenProject/VLCGoogleDriveTableViewController.m

@@ -0,0 +1,299 @@
+//
+//  VLCGoogleDriveTableViewController.m
+//  VLC for iOS
+//
+//  Created by Carola Nitz on 21.09.13.
+//  Copyright (c) 2013 VideoLAN. All rights reserved.
+//
+//  Refer to the COPYING file of the official project for license.
+//
+
+#import "VLCGoogleDriveTableViewController.h"
+#import "VLCGoogleDriveTableViewCell.h"
+#import "VLCGoogleDriveController.h"
+#import "VLCAppDelegate.h"
+#import "VLCPlaylistViewController.h"
+#import "UIBarButtonItem+Theme.h"
+#import "VLCGoogleDriveConstants.h"
+#import "GTMOAuth2ViewControllerTouch.h"
+
+static NSString *const kKeychainItemName = @"Google Drive Quickstart #3";
+
+@interface VLCGoogleDriveTableViewController ()
+{
+    VLCGoogleDriveController *_googleDriveController;
+    GTMOAuth2ViewControllerTouch *_authController;
+    NSString *_currentPath;
+
+    UIBarButtonItem *_backButton;
+    UIBarButtonItem *_backToMenuButton;
+
+    UIBarButtonItem *_numberOfFilesBarButtonItem;
+    UIBarButtonItem *_progressBarButtonItem;
+    UIBarButtonItem *_downloadingBarLabel;
+    UIProgressView *_progressView;
+
+    UIActivityIndicatorView *_activityIndicator;
+}
+
+@end
+
+@implementation VLCGoogleDriveTableViewController
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+
+    self.modalPresentationStyle = UIModalPresentationFormSheet;
+
+    _googleDriveController = [[VLCGoogleDriveController alloc] init];
+    _googleDriveController.delegate = self;
+    [_googleDriveController startSession];
+    self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"DriveWhite"]];
+    self.navigationItem.titleView.contentMode = UIViewContentModeScaleAspectFit;
+
+    _backButton = [UIBarButtonItem themedBackButtonWithTarget:self andSelector:@selector(goBack:)];
+    _backToMenuButton = [UIBarButtonItem themedRevealMenuButtonWithTarget:self andSelector:@selector(goBack:)];
+    self.navigationItem.leftBarButtonItem = _backToMenuButton;
+
+    self.tableView.rowHeight = [VLCGoogleDriveTableViewCell heightOfCell];
+    self.tableView.separatorColor = [UIColor colorWithWhite:.122 alpha:1.];
+    self.view.backgroundColor = [UIColor colorWithWhite:.122 alpha:1.];
+
+    _numberOfFilesBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedString(@"NUM_OF_FILES", @""), 0] style:UIBarButtonItemStylePlain target:nil action:nil];
+    [_numberOfFilesBarButtonItem setTitleTextAttributes:@{ UITextAttributeFont : [UIFont systemFontOfSize:11.] } forState:UIControlStateNormal];
+
+    _progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
+    _progressBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:_progressView];
+    _downloadingBarLabel = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"DOWNLOADING",@"") style:UIBarButtonItemStylePlain target:nil action:nil];
+    [_downloadingBarLabel setTitleTextAttributes:@{ UITextAttributeFont : [UIFont systemFontOfSize:11.] } forState:UIControlStateNormal];
+
+    [_loginToGoogleDriveButton setTitle:NSLocalizedString(@"DROPBOX_LOGIN", @"") forState:UIControlStateNormal];
+
+    [self.navigationController.toolbar setBackgroundImage:[UIImage imageNamed:@"sudHeaderBg"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
+
+    [self _showProgressInToolbar:NO];
+
+    _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+    _activityIndicator.hidesWhenStopped = YES;
+
+    [self.view addSubview:_activityIndicator];
+}
+
+- (GTMOAuth2ViewControllerTouch *)createAuthController
+{
+    _authController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:kGTLAuthScopeDriveFile
+                                                                clientID:kVLCGoogleDriveClientID
+                                                            clientSecret:kVLCGoogleDriveClientSecret
+                                                        keychainItemName:kKeychainItemName
+                                                                delegate:self
+                                                        finishedSelector:@selector(viewController:finishedWithAuth:error:)];
+    return _authController;
+}
+
+- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
+      finishedWithAuth:(GTMOAuth2Authentication *)authResult
+                 error:(NSError *)error
+{
+    if (error != nil)
+    {
+        [self showAlert:@"Authentication Error" message:error.localizedDescription];
+        _googleDriveController.driveService.authorizer = nil;
+    }
+    else
+    {
+        _googleDriveController.driveService.authorizer = authResult;
+    }
+    [self updateViewAfterSessionChange];
+}
+
+- (void)showAlert:(NSString *)title message:(NSString *)message
+{
+    UIAlertView *alert;
+    alert = [[UIAlertView alloc] initWithTitle: title
+                                       message: message
+                                      delegate: nil
+                             cancelButtonTitle: @"OK"
+                             otherButtonTitles: nil];
+    [alert show];
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+    self.navigationController.toolbarHidden = NO;
+    self.navigationController.toolbar.barStyle = UIBarStyleBlack;
+    [self.navigationController.toolbar setBackgroundImage:[UIImage imageNamed:@"bottomBlackBar"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
+    [self updateViewAfterSessionChange];
+    [super viewWillAppear:animated];
+
+    CGRect aiFrame = _activityIndicator.frame;
+    CGSize tvSize = self.tableView.frame.size;
+    aiFrame.origin.x = (tvSize.width - aiFrame.size.width) / 2.;
+    aiFrame.origin.y = (tvSize.height - aiFrame.size.height) / 2.;
+    _activityIndicator.frame = aiFrame;
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+    self.navigationController.toolbarHidden = YES;
+    [super viewWillDisappear:animated];
+}
+
+- (void)_showProgressInToolbar:(BOOL)value
+{
+    if (!value)
+        [self setToolbarItems:@[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], _numberOfFilesBarButtonItem, [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]] animated:YES];
+    else {
+        _progressView.progress = 0.;
+        [self setToolbarItems:@[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], _downloadingBarLabel, _progressBarButtonItem, [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]] animated:YES];
+    }
+}
+
+- (void)_requestInformationForCurrentPath
+{
+    [_activityIndicator startAnimating];
+    [_googleDriveController requestDirectoryListingAtPath:_currentPath];
+
+    self.navigationItem.leftBarButtonItem = ![_currentPath isEqualToString:@"/"] ? _backButton : _backToMenuButton;
+}
+
+#pragma mark - interface interaction
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
+{
+    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
+        return NO;
+    return YES;
+}
+
+- (IBAction)goBack:(id)sender
+{
+    if (![_currentPath isEqualToString:@"/"] && [_currentPath length] > 0) {
+        _currentPath = [_currentPath stringByDeletingLastPathComponent];
+        [self _requestInformationForCurrentPath];
+    } else
+        [[(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController] toggleSidebar:![(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController].sidebarShowing duration:kGHRevealSidebarDefaultAnimationDuration];
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+    return _googleDriveController.currentListFiles.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    static NSString *CellIdentifier = @"GoogleDriveCell";
+
+    VLCGoogleDriveTableViewCell *cell = (VLCGoogleDriveTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+    if (cell == nil)
+        cell = [VLCGoogleDriveTableViewCell cellWithReuseIdentifier:CellIdentifier];
+
+   // cell.fileMetadata = _googleDriveController.currentListFiles[indexPath.row];
+
+    return cell;
+}
+
+#pragma mark - Table view delegate
+
+- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    cell.backgroundColor = (indexPath.row % 2 == 0)? [UIColor blackColor]: [UIColor colorWithWhite:.122 alpha:1.];
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+//    _selectedFile = _googleDriveController.currentListFiles[indexPath.row];
+//    if (!_selectedFile.isDirectory) {
+//        /* selected item is a proper file, ask the user if s/he wants to download it */
+//        UIAlertView * alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"GOOGLE_DRIVE_DOWNLOAD", @"") message:[NSString stringWithFormat:NSLocalizedString(@"GOOGLE_DRIVE_DL_LONG", @""), _selectedFile.filename, [[UIDevice currentDevice] model]] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_CANCEL", @"") otherButtonTitles:NSLocalizedString(@"BUTTON_DOWNLOAD", @""), nil];
+//        [alert show];
+//    } else {
+//        /* dive into subdirectory */
+//        _currentPath = [_currentPath stringByAppendingFormat:@"/%@", _selectedFile.filename];
+//        [self _requestInformationForCurrentPath];
+//        _selectedFile = nil;
+//    }
+
+    [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
+}
+
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+   // if (buttonIndex == 1)
+      //  [_googleDriveController downloadFileToDocumentFolder:_selectedFile];
+
+   // _selectedFile = nil;
+}
+
+#pragma mark - dropbox controller delegate
+
+- (void)mediaListUpdated
+{
+    [_activityIndicator stopAnimating];
+
+    [self.tableView reloadData];
+
+    NSUInteger count = _googleDriveController.currentListFiles.count;
+    if (count == 0)
+        _numberOfFilesBarButtonItem.title = NSLocalizedString(@"NO_FILES", @"");
+    else if (count != 1)
+        _numberOfFilesBarButtonItem.title = [NSString stringWithFormat:NSLocalizedString(@"NUM_OF_FILES", @""), count];
+    else
+        _numberOfFilesBarButtonItem.title = NSLocalizedString(@"ONE_FILE", @"");
+}
+
+- (void)operationWithProgressInformationStarted
+{
+    [self _showProgressInToolbar:YES];
+}
+
+- (void)currentProgressInformation:(float)progress
+{
+    [_progressView setProgress: progress animated:YES];
+}
+
+- (void)operationWithProgressInformationStopped
+{
+    [self _showProgressInToolbar:NO];
+}
+
+#pragma mark - communication with app delegate
+
+- (void)updateViewAfterSessionChange
+{
+    if (![_googleDriveController isAuthorized]) {
+        [self _showLoginPanel];
+        return;
+    } else if (self.loginToGoogleDriveView.superview)
+        [self.loginToGoogleDriveView removeFromSuperview];
+        _currentPath = @"/";
+    [self _requestInformationForCurrentPath];
+}
+
+#pragma mark - login dialog
+
+- (void)_showLoginPanel
+{
+    self.loginToGoogleDriveView.frame = self.tableView.frame;
+    [self.view addSubview:self.loginToGoogleDriveView];
+}
+
+- (IBAction)loginToGoogleDriveAction:(id)sender
+{
+    if (![_googleDriveController isAuthorized]) {
+        _googleDriveController.isAuthorized = NO;
+        [self.navigationController pushViewController:[self createAuthController] animated:YES];
+    } else {
+        _googleDriveController.isAuthorized = YES;
+        [_googleDriveController logout];
+    }
+}
+
+@end

+ 6 - 1
AspenProject/VLCMenuTableViewController.m

@@ -63,7 +63,7 @@
 
     _sectionHeaderTexts = @[@"SECTION_HEADER_LIBRARY", @"SECTION_HEADER_NETWORK", @"Settings"];
     _menuItemsSectionOne = @[@"LIBRARY_ALL_FILES", @"LIBRARY_MUSIC", @"LIBRARY_SERIES"];
-    _menuItemsSectionTwo = @[@"LOCAL_NETWORK", @"OPEN_NETWORK", @"DOWNLOAD_FROM_HTTP", @"WiFi Upload", @"Dropbox"];
+    _menuItemsSectionTwo = @[@"LOCAL_NETWORK", @"OPEN_NETWORK", @"DOWNLOAD_FROM_HTTP", @"WiFi Upload", @"Dropbox", @"Google Drive"];
     _menuItemsSectionThree = @[@"Settings", @"ABOUT_APP"];
 
     _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 44.0f + 20.0f, kGHRevealSidebarWidth, CGRectGetHeight(self.view.bounds) - (44.0f + 20.0f)) style:UITableViewStylePlain];
@@ -195,6 +195,9 @@
         else if ([rawTitle isEqualToString:@"Dropbox"]) {
             cell.textLabel.text = rawTitle;
             cell.imageView.image = [UIImage imageNamed:@"Dropbox"];
+        } else if ([rawTitle isEqualToString:@"Google Drive"]) {
+            cell.textLabel.text = rawTitle;
+            cell.imageView.image = [UIImage imageNamed:@"Drive"];
         } else if ([rawTitle isEqualToString:@"WiFi Upload"]) {
             _uploadLocationLabel = [(VLCWiFiUploadTableViewCell*)cell uploadAddressLabel];
             _uploadButton = [(VLCWiFiUploadTableViewCell*)cell serverOnButton];
@@ -296,6 +299,8 @@
             [self toggleHTTPServer:nil];
         else if (itemIndex == 4)
             viewController = self.appDelegate.dropboxTableViewController;
+        else if (itemIndex == 5)
+            viewController = self.appDelegate.googleDriveTableViewController;
     } else if (sectionNumber == 2) {
         if (itemIndex == 0) {
             if (!self.settingsController)

+ 68 - 355
Resources/VLCDropboxTableViewController.xib

@@ -1,355 +1,68 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
-	<data>
-		<int key="IBDocument.SystemTarget">1296</int>
-		<string key="IBDocument.SystemVersion">12E55</string>
-		<string key="IBDocument.InterfaceBuilderVersion">3084</string>
-		<string key="IBDocument.AppKitVersion">1187.39</string>
-		<string key="IBDocument.HIToolboxVersion">626.00</string>
-		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-			<string key="NS.object.0">2083</string>
-		</object>
-		<array key="IBDocument.IntegratedClassDependencies">
-			<string>IBProxyObject</string>
-			<string>IBUIButton</string>
-			<string>IBUIImageView</string>
-			<string>IBUITableView</string>
-			<string>IBUIView</string>
-		</array>
-		<array key="IBDocument.PluginDependencies">
-			<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-		</array>
-		<object class="NSMutableDictionary" key="IBDocument.Metadata">
-			<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
-			<integer value="1" key="NS.object.0"/>
-		</object>
-		<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
-			<object class="IBProxyObject" id="372490531">
-				<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-			<object class="IBProxyObject" id="975951072">
-				<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-			<object class="IBUIView" id="728160379">
-				<reference key="NSNextResponder"/>
-				<int key="NSvFlags">292</int>
-				<array class="NSMutableArray" key="NSSubviews">
-					<object class="IBUITableView" id="169129295">
-						<reference key="NSNextResponder" ref="728160379"/>
-						<int key="NSvFlags">274</int>
-						<string key="NSFrameSize">{320, 504}</string>
-						<reference key="NSSuperview" ref="728160379"/>
-						<reference key="NSWindow"/>
-						<string key="NSReuseIdentifierKey">_NS:9</string>
-						<object class="NSColor" key="IBUIBackgroundColor" id="651013553">
-							<int key="NSColorSpace">3</int>
-							<bytes key="NSWhite">MAA</bytes>
-						</object>
-						<bool key="IBUIClipsSubviews">YES</bool>
-						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						<bool key="IBUIAlwaysBounceVertical">YES</bool>
-						<bool key="IBUIShowsHorizontalScrollIndicator">NO</bool>
-						<int key="IBUISeparatorStyle">1</int>
-						<int key="IBUISectionIndexMinimumDisplayRowCount">0</int>
-						<bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool>
-						<float key="IBUIRowHeight">44</float>
-						<float key="IBUISectionHeaderHeight">22</float>
-						<float key="IBUISectionFooterHeight">22</float>
-					</object>
-				</array>
-				<string key="NSFrame">{{0, 20}, {320, 504}}</string>
-				<reference key="NSSuperview"/>
-				<reference key="NSWindow"/>
-				<string key="NSReuseIdentifierKey">_NS:9</string>
-				<reference key="IBUIBackgroundColor" ref="651013553"/>
-				<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
-				<object class="IBUISimulatedToolbarMetrics" key="IBUISimulatedBottomBarMetrics">
-					<int key="IBUIBarStyle">1</int>
-				</object>
-				<object class="IBUIScreenMetrics" key="IBUISimulatedDestinationMetrics" id="507962971">
-					<string key="IBUISimulatedSizeMetricsClass">IBUIScreenMetrics</string>
-					<object class="NSMutableDictionary" key="IBUINormalizedOrientationToSizeMap">
-						<bool key="EncodedWithXMLCoder">YES</bool>
-						<array key="dict.sortedKeys">
-							<integer value="1"/>
-							<integer value="3"/>
-						</array>
-						<array key="dict.values">
-							<string>{320, 568}</string>
-							<string>{568, 320}</string>
-						</array>
-					</object>
-					<string key="IBUITargetRuntime">IBCocoaTouchFramework</string>
-					<string key="IBUIDisplayName">Retina 4 Full Screen</string>
-					<int key="IBUIType">2</int>
-				</object>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-			<object class="IBUIView" id="338576143">
-				<reference key="NSNextResponder"/>
-				<int key="NSvFlags">274</int>
-				<array class="NSMutableArray" key="NSSubviews">
-					<object class="IBUIImageView" id="320706770">
-						<reference key="NSNextResponder" ref="338576143"/>
-						<int key="NSvFlags">301</int>
-						<string key="NSFrame">{{71, 192}, {179, 60}}</string>
-						<reference key="NSSuperview" ref="338576143"/>
-						<reference key="NSWindow"/>
-						<reference key="NSNextKeyView" ref="94556417"/>
-						<string key="NSReuseIdentifierKey">_NS:9</string>
-						<bool key="IBUIUserInteractionEnabled">NO</bool>
-						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						<object class="NSCustomResource" key="IBUIImage">
-							<string key="NSClassName">NSImage</string>
-							<string key="NSResourceName">dropbox-white.png</string>
-						</object>
-					</object>
-					<object class="IBUIButton" id="94556417">
-						<reference key="NSNextResponder" ref="338576143"/>
-						<int key="NSvFlags">301</int>
-						<string key="NSFrame">{{120, 312}, {81, 39}}</string>
-						<reference key="NSSuperview" ref="338576143"/>
-						<reference key="NSWindow"/>
-						<string key="NSReuseIdentifierKey">_NS:9</string>
-						<bool key="IBUIOpaque">NO</bool>
-						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-						<int key="IBUIContentHorizontalAlignment">0</int>
-						<int key="IBUIContentVerticalAlignment">0</int>
-						<string key="IBUINormalTitle">Login</string>
-						<object class="NSColor" key="IBUIHighlightedTitleColor">
-							<int key="NSColorSpace">3</int>
-							<bytes key="NSWhite">MQA</bytes>
-						</object>
-						<object class="NSColor" key="IBUINormalTitleColor">
-							<int key="NSColorSpace">1</int>
-							<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
-						</object>
-						<object class="NSColor" key="IBUINormalTitleShadowColor">
-							<int key="NSColorSpace">3</int>
-							<bytes key="NSWhite">MC41AA</bytes>
-						</object>
-						<object class="NSCustomResource" key="IBUINormalBackgroundImage">
-							<string key="NSClassName">NSImage</string>
-							<string key="NSResourceName">menuButton.png</string>
-						</object>
-						<object class="IBUIFontDescription" key="IBUIFontDescription">
-							<int key="type">2</int>
-							<double key="pointSize">15</double>
-						</object>
-						<object class="NSFont" key="IBUIFont">
-							<string key="NSName">Helvetica-Bold</string>
-							<double key="NSSize">15</double>
-							<int key="NSfFlags">16</int>
-						</object>
-					</object>
-				</array>
-				<string key="NSFrameSize">{320, 568}</string>
-				<reference key="NSSuperview"/>
-				<reference key="NSWindow"/>
-				<reference key="NSNextKeyView" ref="320706770"/>
-				<string key="NSReuseIdentifierKey">_NS:9</string>
-				<reference key="IBUIBackgroundColor" ref="651013553"/>
-				<reference key="IBUISimulatedDestinationMetrics" ref="507962971"/>
-				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
-			</object>
-		</array>
-		<object class="IBObjectContainer" key="IBDocument.Objects">
-			<array class="NSMutableArray" key="connectionRecords">
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">loginToDropboxView</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="338576143"/>
-					</object>
-					<int key="connectionID">26</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">loginToDropboxButton</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="94556417"/>
-					</object>
-					<int key="connectionID">27</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">tableView</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="169129295"/>
-					</object>
-					<int key="connectionID">30</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">view</string>
-						<reference key="source" ref="372490531"/>
-						<reference key="destination" ref="728160379"/>
-					</object>
-					<int key="connectionID">31</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchEventConnection" key="connection">
-						<string key="label">loginToDropboxAction:</string>
-						<reference key="source" ref="94556417"/>
-						<reference key="destination" ref="372490531"/>
-						<int key="IBEventType">7</int>
-					</object>
-					<int key="connectionID">25</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">dataSource</string>
-						<reference key="source" ref="169129295"/>
-						<reference key="destination" ref="372490531"/>
-					</object>
-					<int key="connectionID">32</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBCocoaTouchOutletConnection" key="connection">
-						<string key="label">delegate</string>
-						<reference key="source" ref="169129295"/>
-						<reference key="destination" ref="372490531"/>
-					</object>
-					<int key="connectionID">33</int>
-				</object>
-			</array>
-			<object class="IBMutableOrderedSet" key="objectRecords">
-				<array key="orderedObjects">
-					<object class="IBObjectRecord">
-						<int key="objectID">0</int>
-						<array key="object" id="0"/>
-						<reference key="children" ref="1000"/>
-						<nil key="parent"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-1</int>
-						<reference key="object" ref="372490531"/>
-						<reference key="parent" ref="0"/>
-						<string key="objectName">File's Owner</string>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">-2</int>
-						<reference key="object" ref="975951072"/>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">8</int>
-						<reference key="object" ref="338576143"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="94556417"/>
-							<reference ref="320706770"/>
-						</array>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">9</int>
-						<reference key="object" ref="320706770"/>
-						<array class="NSMutableArray" key="children"/>
-						<reference key="parent" ref="338576143"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">20</int>
-						<reference key="object" ref="94556417"/>
-						<reference key="parent" ref="338576143"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">28</int>
-						<reference key="object" ref="728160379"/>
-						<array class="NSMutableArray" key="children">
-							<reference ref="169129295"/>
-						</array>
-						<reference key="parent" ref="0"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">29</int>
-						<reference key="object" ref="169129295"/>
-						<reference key="parent" ref="728160379"/>
-					</object>
-				</array>
-			</object>
-			<dictionary class="NSMutableDictionary" key="flattenedProperties">
-				<string key="-1.CustomClassName">VLCDropboxTableViewController</string>
-				<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="-2.CustomClassName">UIResponder</string>
-				<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="20.CustomClassName">VLCMenuButton</string>
-				<string key="20.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="28.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="8.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-				<string key="9.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-			</dictionary>
-			<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
-			<nil key="activeLocalization"/>
-			<dictionary class="NSMutableDictionary" key="localizations"/>
-			<nil key="sourceID"/>
-			<int key="maxID">33</int>
-		</object>
-		<object class="IBClassDescriber" key="IBDocument.Classes">
-			<array class="NSMutableArray" key="referencedPartialClassDescriptions">
-				<object class="IBPartialClassDescription">
-					<string key="className">VLCDropboxTableViewController</string>
-					<string key="superclassName">UIViewController</string>
-					<object class="NSMutableDictionary" key="actions">
-						<string key="NS.key.0">loginToDropboxAction:</string>
-						<string key="NS.object.0">id</string>
-					</object>
-					<object class="NSMutableDictionary" key="actionInfosByName">
-						<string key="NS.key.0">loginToDropboxAction:</string>
-						<object class="IBActionInfo" key="NS.object.0">
-							<string key="name">loginToDropboxAction:</string>
-							<string key="candidateClassName">id</string>
-						</object>
-					</object>
-					<dictionary class="NSMutableDictionary" key="outlets">
-						<string key="loginToDropboxButton">UIButton</string>
-						<string key="loginToDropboxView">UIView</string>
-						<string key="tableView">UITableView</string>
-					</dictionary>
-					<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
-						<object class="IBToOneOutletInfo" key="loginToDropboxButton">
-							<string key="name">loginToDropboxButton</string>
-							<string key="candidateClassName">UIButton</string>
-						</object>
-						<object class="IBToOneOutletInfo" key="loginToDropboxView">
-							<string key="name">loginToDropboxView</string>
-							<string key="candidateClassName">UIView</string>
-						</object>
-						<object class="IBToOneOutletInfo" key="tableView">
-							<string key="name">tableView</string>
-							<string key="candidateClassName">UITableView</string>
-						</object>
-					</dictionary>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">./Classes/VLCDropboxTableViewController.h</string>
-					</object>
-				</object>
-				<object class="IBPartialClassDescription">
-					<string key="className">VLCMenuButton</string>
-					<string key="superclassName">UIButton</string>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBProjectSource</string>
-						<string key="minorKey">./Classes/VLCMenuButton.h</string>
-					</object>
-				</object>
-			</array>
-		</object>
-		<int key="IBDocument.localizationMode">0</int>
-		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
-		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
-			<real value="1296" key="NS.object.0"/>
-		</object>
-		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
-		<int key="IBDocument.defaultPropertyAccessControl">3</int>
-		<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
-			<string key="dropbox-white.png">{125, 42}</string>
-			<string key="menuButton.png">{63, 39}</string>
-		</dictionary>
-		<string key="IBCocoaTouchPluginVersion">2083</string>
-	</data>
-</archive>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4510" systemVersion="13A603" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
+    <dependencies>
+        <deployment version="1296" defaultVersion="1552" identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="VLCDropboxTableViewController">
+            <connections>
+                <outlet property="loginToDropboxButton" destination="20" id="27"/>
+                <outlet property="loginToDropboxView" destination="8" id="26"/>
+                <outlet property="tableView" destination="29" id="30"/>
+                <outlet property="view" destination="28" id="31"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="28">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <subviews>
+                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="29">
+                    <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                    <connections>
+                        <outlet property="dataSource" destination="-1" id="32"/>
+                        <outlet property="delegate" destination="-1" id="33"/>
+                    </connections>
+                </tableView>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+            <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
+            <simulatedToolbarMetrics key="simulatedBottomBarMetrics" barStyle="black"/>
+            <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
+        </view>
+        <view contentMode="scaleToFill" id="8">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="dropbox-white.png" id="9">
+                    <rect key="frame" x="71" y="192" width="179" height="60"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
+                </imageView>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="20" customClass="VLCMenuButton">
+                    <rect key="frame" x="120" y="312" width="81" height="39"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
+                    <state key="normal" title="Login" backgroundImage="menuButton.png">
+                        <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                    </state>
+                    <state key="highlighted">
+                        <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </state>
+                    <connections>
+                        <action selector="loginToDropboxAction:" destination="-1" eventType="touchUpInside" id="25"/>
+                    </connections>
+                </button>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+            <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="dropbox-white.png" width="125" height="42"/>
+        <image name="menuButton.png" width="63" height="39"/>
+    </resources>
+</document>

+ 53 - 0
Resources/VLCGoogleDriveTableViewCell~ipad.xib

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4510" systemVersion="12E55" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
+    <dependencies>
+        <deployment version="1296" defaultVersion="1296" identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationWidth="10" reuseIdentifier="DropboxCell" rowHeight="76" id="3" customClass="VLCGoogleDriveTableViewCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="80"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3" id="ymH-cz-dYo">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="79"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" id="4">
+                        <rect key="frame" x="5" y="8" width="64" height="64"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    </imageView>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="File Title" lineBreakMode="wordWrap" baselineAdjustment="none" adjustsFontSizeToFit="NO" id="6">
+                        <rect key="frame" x="83" y="21" width="232" height="21"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                        <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </label>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Folder Title" lineBreakMode="wordWrap" baselineAdjustment="none" adjustsFontSizeToFit="NO" id="23">
+                        <rect key="frame" x="83" y="29" width="232" height="21"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                        <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </label>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Subtitle — Subtitle" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="7">
+                        <rect key="frame" x="83" y="44" width="232" height="15"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                        <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </label>
+                </subviews>
+            </tableViewCellContentView>
+            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+            <connections>
+                <outlet property="folderTitleLabel" destination="23" id="24"/>
+                <outlet property="subtitleLabel" destination="7" id="8"/>
+                <outlet property="thumbnailView" destination="4" id="9"/>
+                <outlet property="titleLabel" destination="6" id="10"/>
+            </connections>
+        </tableViewCell>
+    </objects>
+</document>

+ 53 - 0
Resources/VLCGoogleDriveTableViewCell~iphone.xib

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4510" systemVersion="12E55" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
+    <dependencies>
+        <deployment version="1296" defaultVersion="1296" identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationWidth="10" reuseIdentifier="DropboxCell" rowHeight="44" id="3" customClass="VLCGoogleDriveTableViewCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="48"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3" id="aOX-xg-PM4">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="47"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" id="4">
+                        <rect key="frame" x="5" y="8" width="32" height="32"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    </imageView>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="File Title" lineBreakMode="wordWrap" baselineAdjustment="none" adjustsFontSizeToFit="NO" id="6">
+                        <rect key="frame" x="45" y="8" width="270" height="18"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </label>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Folder Title" lineBreakMode="wordWrap" baselineAdjustment="none" adjustsFontSizeToFit="NO" id="23">
+                        <rect key="frame" x="45" y="15" width="270" height="18"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </label>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Subtitle — Subtitle" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="7">
+                        <rect key="frame" x="45" y="25" width="270" height="15"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                        <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </label>
+                </subviews>
+            </tableViewCellContentView>
+            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+            <connections>
+                <outlet property="folderTitleLabel" destination="23" id="24"/>
+                <outlet property="subtitleLabel" destination="7" id="8"/>
+                <outlet property="thumbnailView" destination="4" id="9"/>
+                <outlet property="titleLabel" destination="6" id="10"/>
+            </connections>
+        </tableViewCell>
+    </objects>
+</document>

+ 68 - 0
Resources/VLCGoogleDriveTableViewController.xib

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4510" systemVersion="13A603" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
+    <dependencies>
+        <deployment version="1296" defaultVersion="1552" identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="VLCGoogleDriveTableViewController">
+            <connections>
+                <outlet property="loginToGoogleDriveButton" destination="20" id="TtB-EO-dc5"/>
+                <outlet property="loginToGoogleDriveView" destination="8" id="6R4-FE-vqb"/>
+                <outlet property="tableView" destination="29" id="30"/>
+                <outlet property="view" destination="28" id="31"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="28">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <subviews>
+                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="29">
+                    <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                    <connections>
+                        <outlet property="dataSource" destination="-1" id="32"/>
+                        <outlet property="delegate" destination="-1" id="33"/>
+                    </connections>
+                </tableView>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+            <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
+            <simulatedToolbarMetrics key="simulatedBottomBarMetrics" barStyle="black"/>
+            <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
+        </view>
+        <view contentMode="scaleToFill" id="8">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="DriveWhite.png" id="9">
+                    <rect key="frame" x="77" y="202" width="162" height="48"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
+                </imageView>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="20" customClass="VLCMenuButton">
+                    <rect key="frame" x="120" y="312" width="81" height="39"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
+                    <state key="normal" title="Login" backgroundImage="menuButton.png">
+                        <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                    </state>
+                    <state key="highlighted">
+                        <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </state>
+                    <connections>
+                        <action selector="loginToGoogleDriveAction:" destination="-1" eventType="touchUpInside" id="JPk-kM-vDi"/>
+                    </connections>
+                </button>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+            <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="DriveWhite.png" width="81" height="24"/>
+        <image name="menuButton.png" width="63" height="39"/>
+    </resources>
+</document>

+ 68 - 0
VLC for iOS.xcodeproj/project.pbxproj

@@ -189,6 +189,7 @@
 		7D6BD1851762026700AD311A /* thumbOverlay@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6BD1811762026700AD311A /* thumbOverlay@2x.png */; };
 		7D6BD1861762026700AD311A /* thumbOverlayPhone.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6BD1821762026700AD311A /* thumbOverlayPhone.png */; };
 		7D6BD1871762026700AD311A /* thumbOverlay.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D6BD1831762026700AD311A /* thumbOverlay.png */; };
+		7D711ADA18227A490094E4F0 /* GTMOAuth2ViewTouch.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D711AD918227A490094E4F0 /* GTMOAuth2ViewTouch.xib */; };
 		7D8EEC181804217800A6F16E /* VLCFuturePlaylistCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D8EEC171804217800A6F16E /* VLCFuturePlaylistCollectionViewCell.xib */; };
 		7D93044117B67C4F0054EAC6 /* VLCLocalServerListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D93043F17B67C4F0054EAC6 /* VLCLocalServerListViewController.m */; };
 		7D93044517B684CF0054EAC6 /* VLCLocalNetworkListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D93044417B684CF0054EAC6 /* VLCLocalNetworkListCell.m */; };
@@ -259,6 +260,14 @@
 		7DF65C2D174FF3F400F43330 /* VLCDropboxTableViewCell~iphone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DF65C2C174FF3F400F43330 /* VLCDropboxTableViewCell~iphone.xib */; };
 		7DF7CA0717650C2A00C61739 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DF7CA0617650C2A00C61739 /* AVFoundation.framework */; };
 		7DF7E791175F47DC0018858D /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DF7E790175F47DC0018858D /* MediaPlayer.framework */; };
+		9B2E0CF417FB71E90098E3DF /* libGTLTouchStaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E0CF317FB71E80098E3DF /* libGTLTouchStaticLib.a */; };
+		9B51719D17EDED9700F8FBA7 /* VLCGoogleDriveController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B51719C17EDED9700F8FBA7 /* VLCGoogleDriveController.m */; };
+		9B5171A017EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B51719F17EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.m */; };
+		9B5171A317EDEEA200F8FBA7 /* VLCGoogleDriveTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B5171A217EDEEA100F8FBA7 /* VLCGoogleDriveTableViewController.m */; };
+		9B5BEF2917FBAEA50016F9CB /* GTLDrive_Sources.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B5BEF2717FBAEA50016F9CB /* GTLDrive_Sources.m */; };
+		9B7A958E1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7A958B1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~ipad.xib */; };
+		9B7A958F1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~iphone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7A958C1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~iphone.xib */; };
+		9B7A95901821A14A00DB8427 /* VLCGoogleDriveTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7A958D1821A14A00DB8427 /* VLCGoogleDriveTableViewController.xib */; };
 		A7035BBE174519600057DFA7 /* iTunesArtwork in Resources */ = {isa = PBXBuildFile; fileRef = A7035BBD174519600057DFA7 /* iTunesArtwork */; };
 		A7924696170F0BA90036AAF2 /* libMediaLibraryKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A7924695170F0BA90036AAF2 /* libMediaLibraryKit.a */; };
 		A79246A7170F0ED20036AAF2 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A7924698170F0ED20036AAF2 /* Default-568h@2x.png */; };
@@ -612,6 +621,7 @@
 		7D6BD1821762026700AD311A /* thumbOverlayPhone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumbOverlayPhone.png; sourceTree = "<group>"; };
 		7D6BD1831762026700AD311A /* thumbOverlay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumbOverlay.png; sourceTree = "<group>"; };
 		7D6D13591758D1A00007EA9A /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
+		7D711AD918227A490094E4F0 /* GTMOAuth2ViewTouch.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = GTMOAuth2ViewTouch.xib; path = ImportedSources/GDrive/OAuth2/Touch/GTMOAuth2ViewTouch.xib; sourceTree = SOURCE_ROOT; };
 		7D7DA52F1768A53200C7E95D /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
 		7D7DA5301768A53200C7E95D /* id */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = id; path = "id.lproj/badgeUnread@2x~ipad.png"; sourceTree = "<group>"; };
 		7D7DA5311768A53200C7E95D /* id */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = id; path = "id.lproj/badgeUnread@2x~iphone.png"; sourceTree = "<group>"; };
@@ -741,6 +751,19 @@
 		7DF65C2C174FF3F400F43330 /* VLCDropboxTableViewCell~iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCDropboxTableViewCell~iphone.xib"; path = "../Resources/VLCDropboxTableViewCell~iphone.xib"; sourceTree = "<group>"; };
 		7DF7CA0617650C2A00C61739 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
 		7DF7E790175F47DC0018858D /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
+		9B2E0CF317FB71E80098E3DF /* libGTLTouchStaticLib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libGTLTouchStaticLib.a; path = "../google-api/Source/build/Debug-iphoneos/libGTLTouchStaticLib.a"; sourceTree = "<group>"; };
+		9B51719B17EDED9700F8FBA7 /* VLCGoogleDriveController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCGoogleDriveController.h; sourceTree = "<group>"; };
+		9B51719C17EDED9700F8FBA7 /* VLCGoogleDriveController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCGoogleDriveController.m; sourceTree = "<group>"; };
+		9B51719E17EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCGoogleDriveTableViewCell.h; sourceTree = "<group>"; };
+		9B51719F17EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCGoogleDriveTableViewCell.m; sourceTree = "<group>"; };
+		9B5171A117EDEEA100F8FBA7 /* VLCGoogleDriveTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCGoogleDriveTableViewController.h; sourceTree = "<group>"; };
+		9B5171A217EDEEA100F8FBA7 /* VLCGoogleDriveTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCGoogleDriveTableViewController.m; sourceTree = "<group>"; };
+		9B5171A417EDF03700F8FBA7 /* VLCGoogleDriveConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCGoogleDriveConstants.h; sourceTree = "<group>"; };
+		9B5BEF2717FBAEA50016F9CB /* GTLDrive_Sources.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GTLDrive_Sources.m; path = ImportedSources/GDrive/Services/Drive/Generated/GTLDrive_Sources.m; sourceTree = SOURCE_ROOT; };
+		9B5BEF2817FBAEA50016F9CB /* GTLDrive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GTLDrive.h; path = ImportedSources/GDrive/Services/Drive/Generated/GTLDrive.h; sourceTree = SOURCE_ROOT; };
+		9B7A958B1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCGoogleDriveTableViewCell~ipad.xib"; path = "Resources/VLCGoogleDriveTableViewCell~ipad.xib"; sourceTree = SOURCE_ROOT; };
+		9B7A958C1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCGoogleDriveTableViewCell~iphone.xib"; path = "Resources/VLCGoogleDriveTableViewCell~iphone.xib"; sourceTree = SOURCE_ROOT; };
+		9B7A958D1821A14A00DB8427 /* VLCGoogleDriveTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCGoogleDriveTableViewController.xib; path = Resources/VLCGoogleDriveTableViewController.xib; sourceTree = SOURCE_ROOT; };
 		A7035BBD174519600057DFA7 /* iTunesArtwork */ = {isa = PBXFileReference; lastKnownFileType = file; path = iTunesArtwork; sourceTree = "<group>"; };
 		A7924695170F0BA90036AAF2 /* libMediaLibraryKit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMediaLibraryKit.a; path = External/MediaLibraryKit/libMediaLibraryKit.a; sourceTree = "<group>"; };
 		A7924698170F0ED20036AAF2 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
@@ -898,6 +921,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				9B2E0CF417FB71E90098E3DF /* libGTLTouchStaticLib.a in Frameworks */,
 				CCE2A22E17A5859E00D9EAAD /* CoreText.framework in Frameworks */,
 				7DF7CA0717650C2A00C61739 /* AVFoundation.framework in Frameworks */,
 				7DF7E791175F47DC0018858D /* MediaPlayer.framework in Frameworks */,
@@ -1412,6 +1436,7 @@
 		7D94FCDD16DE7D1000F2623B /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				9B2E0CF317FB71E80098E3DF /* libGTLTouchStaticLib.a */,
 				CCE2A22D17A5859E00D9EAAD /* CoreText.framework */,
 				7DF7CA0617650C2A00C61739 /* AVFoundation.framework */,
 				7DF7E790175F47DC0018858D /* MediaPlayer.framework */,
@@ -1445,6 +1470,7 @@
 				7DD8DDAF17C915F400E7AE4B /* VLCFixups.h */,
 				7D94FCED16DE7D1000F2623B /* VLCAppDelegate.h */,
 				7D94FCEE16DE7D1000F2623B /* VLCAppDelegate.m */,
+				9B51719A17EDEC8900F8FBA7 /* GoogleDrive Integration */,
 				A7D03A4817A4249F0022C16F /* MediaDiscovering */,
 				7D2339AB176DE70E008D223C /* Menu */,
 				7D5F7ABA175265CB006CCCFA /* HTTP Connectivity */,
@@ -1476,6 +1502,9 @@
 		7DADC55C1704FAA8001DAC63 /* XIBs */ = {
 			isa = PBXGroup;
 			children = (
+				9B7A958B1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~ipad.xib */,
+				9B7A958C1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~iphone.xib */,
+				9B7A958D1821A14A00DB8427 /* VLCGoogleDriveTableViewController.xib */,
 				7DC72D6817B820C8008A26D0 /* VLCNetworkLoginViewController.xib */,
 				7D93045A17B6ACCF0054EAC6 /* VLCWiFiUploadTableViewCell.xib */,
 				7D93044617B687C90054EAC6 /* VLCLocalNetworkListCell~ipad.xib */,
@@ -1496,6 +1525,7 @@
 				7D5E39C5174FBAF3007DAFA1 /* VLCDropboxTableViewController.xib */,
 				7D5E39D0174FCF43007DAFA1 /* VLCDropboxTableViewCell~ipad.xib */,
 				7DF65C2C174FF3F400F43330 /* VLCDropboxTableViewCell~iphone.xib */,
+				7D711AD918227A490094E4F0 /* GTMOAuth2ViewTouch.xib */,
 			);
 			name = XIBs;
 			sourceTree = "<group>";
@@ -1503,6 +1533,7 @@
 		7DADC5601704FACC001DAC63 /* Imported */ = {
 			isa = PBXGroup;
 			children = (
+				9B2E0CED17FB5B3F0098E3DF /* GoogleDrive */,
 				A7B5316017E3728D00EAE4B3 /* upnpx */,
 				7D6B08CA174D65B400A05173 /* InAppSettingsKit */,
 				A7A0E9EB174BA66000162F25 /* PAPasscode */,
@@ -1591,6 +1622,29 @@
 			name = menu;
 			sourceTree = "<group>";
 		};
+		9B2E0CED17FB5B3F0098E3DF /* GoogleDrive */ = {
+			isa = PBXGroup;
+			children = (
+				9B5BEF2717FBAEA50016F9CB /* GTLDrive_Sources.m */,
+				9B5BEF2817FBAEA50016F9CB /* GTLDrive.h */,
+			);
+			name = GoogleDrive;
+			sourceTree = "<group>";
+		};
+		9B51719A17EDEC8900F8FBA7 /* GoogleDrive Integration */ = {
+			isa = PBXGroup;
+			children = (
+				9B5171A417EDF03700F8FBA7 /* VLCGoogleDriveConstants.h */,
+				9B5171A117EDEEA100F8FBA7 /* VLCGoogleDriveTableViewController.h */,
+				9B5171A217EDEEA100F8FBA7 /* VLCGoogleDriveTableViewController.m */,
+				9B51719E17EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.h */,
+				9B51719F17EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.m */,
+				9B51719B17EDED9700F8FBA7 /* VLCGoogleDriveController.h */,
+				9B51719C17EDED9700F8FBA7 /* VLCGoogleDriveController.m */,
+			);
+			name = "GoogleDrive Integration";
+			sourceTree = "<group>";
+		};
 		A7924697170F0ED20036AAF2 /* Resources */ = {
 			isa = PBXGroup;
 			children = (
@@ -1847,6 +1901,7 @@
 				7DA8B0FB173318E80029698C /* SourceCodePro-Regular.ttf in Resources */,
 				7DC87AF217413EE3009DC250 /* VLCPlaylistGridView.xib in Resources */,
 				A7FF9F3E17428C1900999819 /* DeleteButton.png in Resources */,
+				9B7A95901821A14A00DB8427 /* VLCGoogleDriveTableViewController.xib in Resources */,
 				A7FF9F4017428C3800999819 /* DeleteButton@2x.png in Resources */,
 				A7035BBE174519600057DFA7 /* iTunesArtwork in Resources */,
 				29125E5617492219003F03E5 /* index.html in Resources */,
@@ -1939,6 +1994,7 @@
 				7D1AC30817629AB600BD2EB5 /* ratioIcon.png in Resources */,
 				7D8EEC181804217800A6F16E /* VLCFuturePlaylistCollectionViewCell.xib in Resources */,
 				7D1AC30917629AB600BD2EB5 /* ratioIcon@2x.png in Resources */,
+				9B7A958F1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~iphone.xib in Resources */,
 				7D1AC30C17629D4600BD2EB5 /* title.png in Resources */,
 				7D1AC30D17629D4600BD2EB5 /* title@2x.png in Resources */,
 				7DEB3B5D17647B240038FC70 /* bottomBlackBar@2x.png in Resources */,
@@ -1975,6 +2031,7 @@
 				A7990064176E9352009E8267 /* libraryBackground.png in Resources */,
 				7DD2A3A9179C04A7003EB537 /* OpenSans-Regular.ttf in Resources */,
 				7D2A34A41805CDBA004078AA /* gradient-cell-ios7.png in Resources */,
+				9B7A958E1821A14A00DB8427 /* VLCGoogleDriveTableViewCell~ipad.xib in Resources */,
 				7D93044817B687C90054EAC6 /* VLCLocalNetworkListCell~ipad.xib in Resources */,
 				7D93044917B687C90054EAC6 /* VLCLocalNetworkListCell~iphone.xib in Resources */,
 				7D93045B17B6ACCF0054EAC6 /* VLCWiFiUploadTableViewCell.xib in Resources */,
@@ -1987,6 +2044,7 @@
 				7D16035F17BF9FE600F29B34 /* headerSidebar@2x.png in Resources */,
 				7D16036017BF9FE600F29B34 /* headerSidebar.png in Resources */,
 				7D0699D617CB1FAE00713BEB /* Settings@2x.png in Resources */,
+				7D711ADA18227A490094E4F0 /* GTMOAuth2ViewTouch.xib in Resources */,
 				7D0699D717CB1FAE00713BEB /* TVShows.png in Resources */,
 				7D0699D817CB1FAE00713BEB /* TVShows@2x.png in Resources */,
 				7D0699D917CB1FAE00713BEB /* WifiUp.png in Resources */,
@@ -2074,6 +2132,7 @@
 				7D6B08F3174D65B500A05173 /* IASKPSSliderSpecifierViewCell.m in Sources */,
 				7D6B08F4174D65B500A05173 /* IASKPSTextFieldSpecifierViewCell.m in Sources */,
 				7D6B08F5174D65B500A05173 /* IASKPSTitleValueSpecifierViewCell.m in Sources */,
+				9B5BEF2917FBAEA50016F9CB /* GTLDrive_Sources.m in Sources */,
 				7D6B08F6174D65B500A05173 /* IASKSlider.m in Sources */,
 				7D6B08F7174D65B500A05173 /* IASKSwitch.m in Sources */,
 				7D6B08F8174D65B500A05173 /* IASKTextField.m in Sources */,
@@ -2102,6 +2161,9 @@
 				A7B5315F17E35B6E00EAE4B3 /* VLCThumbnailsCache.m in Sources */,
 				7D9F7FB117F969B0000A6500 /* VLCSidebarViewCell.m in Sources */,
 				7D1AA4DE17FDA47C00D6D9F9 /* VLCPlaylistCollectionViewCell.m in Sources */,
+				9B51719D17EDED9700F8FBA7 /* VLCGoogleDriveController.m in Sources */,
+				9B5171A017EDEE8000F8FBA7 /* VLCGoogleDriveTableViewCell.m in Sources */,
+				9B5171A317EDEEA200F8FBA7 /* VLCGoogleDriveTableViewController.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2367,6 +2429,7 @@
 					"$(SRCROOT)/External/MediaLibraryKit/include",
 					"$(SRCROOT)/ImportedSources/upnpx/src/api",
 					"$(SRCROOT)/ImportedSources/upnpx/src/port/ios",
+					"$(SRCROOT)/ImportedSources/GDrive/**",
 				);
 				INFOPLIST_FILE = "AspenProject/VLC for iOS-Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 6.1;
@@ -2375,6 +2438,7 @@
 					"\"$(SRCROOT)/External/MediaLibraryKit\"",
 					"\"$(SRCROOT)/External/MobileVLCKit\"",
 					"\"$(SRCROOT)/External/upnpx\"",
+					"\"$(SRCROOT)/External/gtl\"",
 					"\"$(SDKROOT)/usr/lib/system\"",
 				);
 				ONLY_ACTIVE_ARCH = YES;
@@ -2405,6 +2469,7 @@
 					"$(SRCROOT)/External/MediaLibraryKit/include",
 					"$(SRCROOT)/ImportedSources/upnpx/src/api",
 					"$(SRCROOT)/ImportedSources/upnpx/src/port/ios",
+					"$(SRCROOT)/ImportedSources/GDrive/**",
 				);
 				INFOPLIST_FILE = "AspenProject/VLC for iOS-Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 6.1;
@@ -2413,6 +2478,7 @@
 					"\"$(SRCROOT)/External/MediaLibraryKit\"",
 					"\"$(SRCROOT)/External/MobileVLCKit\"",
 					"\"$(SRCROOT)/External/upnpx\"",
+					"\"$(SRCROOT)/External/gtl\"",
 					"\"$(SDKROOT)/usr/lib/system\"",
 				);
 				ONLY_ACTIVE_ARCH = NO;
@@ -2470,6 +2536,7 @@
 					"$(SRCROOT)/External/MediaLibraryKit/include",
 					"$(SRCROOT)/ImportedSources/upnpx/src/api",
 					"$(SRCROOT)/ImportedSources/upnpx/src/port/ios",
+					"$(SRCROOT)/ImportedSources/GDrive/**",
 				);
 				INFOPLIST_FILE = "AspenProject/VLC for iOS-Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 6.1;
@@ -2478,6 +2545,7 @@
 					"\"$(SRCROOT)/External/MediaLibraryKit\"",
 					"\"$(SRCROOT)/External/MobileVLCKit\"",
 					"\"$(SRCROOT)/External/upnpx\"",
+					"\"$(SRCROOT)/External/gtl\"",
 					"\"$(SDKROOT)/usr/lib/system\"",
 				);
 				ONLY_ACTIVE_ARCH = NO;

+ 2 - 0
buildAspenProject.sh

@@ -198,6 +198,7 @@ fi
 framework_build="${aspen_root_dir}/ImportedSources/VLCKit/${xcbuilddir}"
 mlkit_build="${aspen_root_dir}/ImportedSources/MediaLibraryKit/${xcbuilddir}"
 upnpx_build="${aspen_root_dir}/ImportedSources/upnpx/projects/xcode4/upnpx/${xcbuilddir}"
+gtl_build="${aspen_root_dir}/ImportedSources/GDrive/${xcbuilddir}"
 
 spushd MediaLibraryKit
 rm -f External/MobileVLCKit
@@ -209,6 +210,7 @@ spopd #ImportedSources
 ln -sf ${framework_build} External/MobileVLCKit
 ln -sf ${mlkit_build} External/MediaLibraryKit
 ln -sf ${upnpx_build} External/upnpx
+ln -sf ${gtl_build} External/gtl
 
 #
 # Build time