File Browser Code Listing

FileListViewController.h

class BaseAppDelegate;

@interface FileListViewController : UITableViewController <UIAlertViewDelegate, OSFileManagerProtocol> {
    NSMetadataQuery* _query;
    NSMutableArray* _fileList;
    NSIndexPath *_lastSelection;

    NSArray* _localDocuments;
    UIAlertView* _iCloudFileDeleteAlert;
    
    bool _clearFiles;
    bool _deletingDocument;
    bool _creatingDocument;
    bool _fileIsOpen;
    
}

@property (nonatomic, strong) BaseAppDelegate *appDelegate;

@property (nonatomic, strong) NSString *fileExtension;
@property (nonatomic, strong) NSString *fileImageName;
@property (nonatomic, strong) NSString *openingViewControllerNIB;

- (void)showDetailsForSelf;
- (void)updateList;
- (void)updateFileList;
- (void)fileHasBeenCreated:(NSURL*)fileURL;
- (void)fileHasBeenDeleted:(NSURL*)fileURL;
- (void)fileHasBeenOpened:(NSURL*)fileURL;
- (void)fileHasBeenClosed:(NSURL*)fileURL;

@end

FileListViewController.m

@implementation FileListViewController

@synthesize appDelegate;
@synthesize fileExtension = _fileExtension;
@synthesize fileImageName = _fileImageName;
@synthesize openingViewControllerNIB = _openingViewControllerNIB;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
            self.clearsSelectionOnViewWillAppear = NO;
            self.preferredContentSize = CGSizeMake(320.0, 600.0);
        }
        
        _fileList = [[NSMutableArray alloc] init];
        _clearFiles = NO;
        _fileIsOpen = NO;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateCloudEnabled) name:ICloudStateUpdatedNotification object:nil];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fileCreated) name:OSFileCreatedNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fileDeleted) name:OSFileDeletedNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fileClosed) name:OSFileClosedNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(filesUpdated) name:OSFilesUpdatedNotification object:nil];
        
        _deletingDocument = NO;
        _creatingDocument = NO;
        
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
/*! Updates the list of files displayed in the UITableView by getting an updated list
    from the CloudManager.
 
 */
- (void)updateFileList
{
    //LOG(@"updateFileList called.");

    [_fileList removeAllObjects];

    _fileList = [[OSDocumentManager sharedManager] getFileList];
    
}

- (void)updateCloudEnabled
{
    // If the iCloud state changed, i.e. a sign out occurred, close any DetailViewControllers which are showing documents and update the file list.
    //LOG(@"updateCloudEnabled called, notification sent");
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        [self.navigationController popToRootViewControllerAnimated:NO];
    }
    else {
        OpeningViewController* emptyDetailController = [[OpeningViewController alloc] initWithNibName:_openingViewControllerNIB bundle:nil];
        self.splitViewController.viewControllers = [NSArray arrayWithObjects:self.navigationController, emptyDetailController, nil];
    }
    
    [self updateFileList];
    [self.tableView reloadData];
}

- (void)documentFinishedClosing:(NSNotification*)notification;
{
    if (![[OSDocumentManager sharedManager] isCloudEnabled]) {
        // When using iCloud, we can rely on metadata queries to update the file list, but when using local storage, we'll use this notification to tell us to update.
        [self updateFileList];
    }
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown : YES;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.tableView.allowsSelectionDuringEditing = NO;
    
    UIBarButtonItem* plusButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createFile)];
    self.navigationItem.rightBarButtonItem = plusButton;
    
    self.navigationItem.leftBarButtonItem = self.editButtonItem;
    
    [self updateFileList];
    
    UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
    
    refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
    
    [refresh addTarget:self action:@selector(updateList) forControlEvents:UIControlEventValueChanged];
    
    self.refreshControl = refresh;
    
    
}
- (void)stopRefresh {
    
    [self.refreshControl endRefreshing];
    
}
- (void)viewDidUnload
{   //LOG(@"viewDidUnload called");
    [super viewDidUnload];
    
    _fileList = nil;

}
// Refresh the list
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self updateList];
}

// Refresh the list - we don't need this so do nothing
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    //[self updateList];
}
/*! Update the file list, refresh the tableView and stop the refreshIndicator if its running
 
 */
- (void)updateList {
    [self updateFileList];
    [self.tableView reloadData];
    [self performSelector:@selector(stopRefresh) withObject:nil afterDelay:0.5];
}
/*! Prompt the user for a new file name
 */
- (void)createFile
{
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Create New Project" message:@"Enter project name" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Done", nil];
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    UITextField *projName = [alert textFieldAtIndex:0];
    projName.text = @"New Project";
    [projName selectAll:nil];
    [alert show];
}
/*! Select a file and open it using the AppDelegate
 
 */
- (void)selectFileAtIndexPath:(NSIndexPath*)indexPath create:(BOOL)create
{
    // Remember the selection so we can update the file's timestamp when we come back
    // to show the last time it was updated.
    _lastSelection = indexPath;

    // Don't allow another one until this request is completed
    _creatingDocument = YES;

    if (create) {

        //NSLog(@"Create a new file");
        [[OSDocumentManager sharedManager] createNewFile:[[_fileList objectAtIndex:indexPath.row] url] requester:self];
        
    } else {  // Just open it
        
        //NSLog(@"selected file %@",[[_fileList objectAtIndex:indexPath.row] url]);
        [[OSDocumentManager sharedManager] createNewFile:[[_fileList objectAtIndex:indexPath.row] url] requester:self];
                
    }
}
/*! Callback from CloudManager to let us know the file has been opened.  This always gets called if it's
    and existing file so we assume the user wants to open for editing.
 
 */
- (void)fileHasBeenOpened:(NSURL*)fileURL {
    
        LOG(@"fileOpened called");
        _fileIsOpen = YES;
        _creatingDocument = NO;

        MenuViewController *menuViewController = [[MenuViewController alloc] initWithNibName:@"MainMenuViewController" bundle:nil];
        menuViewController.appDelegate = self.appDelegate;
        menuViewController.managedObjectContext = [[OSDocumentManager sharedManager] managedObjectContext];
        menuViewController.title = @"Menu";
        menuViewController.openingViewController=self.appDelegate.openingViewController;
        [menuViewController.openingViewController setFilesName:[[fileURL lastPathComponent] stringByDeletingPathExtension]];
        [menuViewController.openingViewController setFilesDate:[[OSDocumentManager sharedManager] getFileDate:fileURL] deviceName:nil];
        
        [self.navigationController pushViewController:menuViewController animated:YES];
    
    
        if ([[OSDocumentManager sharedManager] canUseICloud])
            [[OSDocumentManager sharedManager] postUIUpdateNotification];
        
}
/*! Callback from CloudManager to let us know the file has been created. If it's a new file
    then this always gets called so the user has to then select the item to open it for editing
 
 */
- (void)fileHasBeenCreated:(NSURL*)fileURL {
    
    _creatingDocument = NO;
    [self updateList];
    
}
/*! Callback from CloudManager to let us know the file has been created
 
 */
- (void)fileHasBeenClosed:(NSURL*)fileURL {
    
    _fileIsOpen = NO;
    [self updateList];
    
}
/*! Callback from CloudManager to let us know the file has been deleted
 
 */
- (void)fileHasBeenDeleted:(NSURL*)fileURL {
    
    _deletingDocument = NO;
    [self updateList];
    
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    // Otherwise we must be creating a new file
    if (buttonIndex != alertView.cancelButtonIndex) {
        
        // get the user entered file name
        NSString* userFilename = [[alertView textFieldAtIndex:0] text];
        NSString *fileName;
        
        // Check if iCloud preference is ON and iCloud is available then add UUID
        if ([[OSDocumentManager sharedManager] canUseICloud]) {
            //FLOG(@" iCloud is available so create new filename with UUID");
            // Append a UUID to guarantee its UNiQUE just in case the user uses the same name to create a new file on a different device!
            NSString *uuidString = [[NSUUID UUID] UUIDString];
            
            fileName = [NSString stringWithFormat:@"%@_UUID_%@",userFilename, uuidString];
            
        } else {
            
            //FLOG(@" iCloud is NOT available so create new filename without UUID");
            fileName = userFilename;
            
        }
        
        NSURL* fileURL = [[[OSDocumentManager sharedManager] documentsDirectoryURL] URLByAppendingPathComponent:fileName];
        
        // Getting OSDocumentManager to create and let us know once its done, then we refresh the table
        //  get this working and then show the item but set it disabled until we get the callback to prevent
        //  the user from being able to open it before it has been created.
        _creatingDocument = YES;
        [[OSDocumentManager sharedManager] createNewFile:fileURL requester:self];
        
        return;
 
    }
}
// Returns the user entered filename because we have appended a UUID to guarantee uniqueness in iCloud
- (NSString*)userFilename:(NSString *)filename {
    NSArray *components = [filename componentsSeparatedByString:@"_UUID_"];
    return [components objectAtIndex:0];
}
/*! Updates the date displayed in the UITabelView cell
 
 */
- (void)updateFileDate {
    //LOG(@"updateFileDate called");
    if (_lastSelection == nil) return;
    
    FileRepresentation* file = [_fileList objectAtIndex:_lastSelection.row];
    
    FileTableViewCell *cell = (FileTableViewCell *)[self.tableView cellForRowAtIndexPath:_lastSelection];
    
    cell.detailTextLabel.text = [file modifiedDate];
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [_fileList count];
}

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

    FileTableViewCell *cell = (FileTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"FileTableViewCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }
    
    // Configure the cell.
    FileRepresentation* fileRepresentation = _fileList[indexPath.row];
    cell.textLabel.text = [self userFilename:[fileRepresentation.fileName stringByDeletingPathExtension]];
    
    cell.detailTextLabel.text = [fileRepresentation modifiedDate];
    
    
    cell.accessoryView=nil;
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    [cell.progressIndicator setHidden:YES];

    cell.imageView.image = [UIImage imageNamed:_fileImageName];
    
    // Disable any user interaction while processing a request
    if (_fileIsOpen || _creatingDocument || _deletingDocument) {
    
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.textLabel.textColor = [UIColor grayColor];
        
    } else {
        
        cell.textLabel.textColor = [UIColor blackColor];
        cell.selectionStyle = UITableViewCellSelectionStyleDefault;
        
    }
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (_fileIsOpen || _creatingDocument || _deletingDocument) {
        
    } else {
        [self selectFileAtIndexPath:indexPath create:NO];
    }
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Perform an asynchronous coordinated delete of the file
    NSURL* fileURL = [[_fileList objectAtIndex:indexPath.row] url];
    _deletingDocument = YES;
    [[OSDocumentManager sharedManager] deleteDocumentAtURL:fileURL];
    
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return ![indexPath isEqual:[tableView indexPathForSelectedRow]];
}


/*! Updates list when notification received that files have changed. Resets 
    _deletingDocument when its called.
 
 */
- (void)filesUpdated {
    FLOG(@"filesUpdated called");
    _deletingDocument = NO;
    [self updateList];
}
/*! Updates list when notification received that files have changed. Resets
 _deletingDocument when its called.
 
 */
- (void)fileDeleted {
    FLOG(@"fileDeleted called");
    _deletingDocument = NO;
    [self updateList];
}
/*! Updates list when notification received that files have changed. Resets
  _deletingDocument when its called.
  
  */
- (void)fileCreated {
    FLOG(@"fileCreated called");
    _creatingDocument = NO;
    [self updateList];
}
/*! Tells us when the file is closed.
 
 */
- (void)fileClosed {
    FLOG(@"fileClosed called");
    _fileIsOpen = NO;
    [self.tableView reloadData];
}


/*! This always gets called when we select a folder object or when we navigate back because it is triggered
    by showing of the MasterViewController in AppDelegate...
 
 */
- (void)showDetailsForSelf
{
    //LOG(@"showDetailsForSelf called");
    
    [self.appDelegate.detailViewManager setOpeningDetailView];
    [self.appDelegate.detailViewManager.openingDetailViewController setFilesName:@"" ];
    [self.appDelegate.detailViewManager.openingDetailViewController setFilesDate:@"" deviceName:@""];
    
    // Restart the query to get any changed files
    [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
    [self updateFileDate];
    
}
@end

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s