#import <cassert> #import "FileCollectionViewController.h" #import "FileContentViewController.h" #import "FileShortcutView.h" #import "Shortcuts.h" #import "Constants.h" //C++ imports. #import "FileUtils.h" @implementation FileCollectionViewController { __weak IBOutlet UIScrollView *scrollView; __weak IBOutlet UIView *fileOpenView; __weak IBOutlet UITextField *fileNameField; NSMutableArray *fileContainers; BOOL viewDidAppear; __weak FileShortcutView *fileToDelete; BOOL locked; } //____________________________________________________________________________________________________ - (instancetype) initWithCoder : (NSCoder *) aDecoder { if (self = [super initWithCoder : aDecoder]) { fileContainers = [[NSMutableArray alloc] init]; viewDidAppear = NO; locked = NO; } return self; } #pragma mark - View lifecycle //____________________________________________________________________________________________________ - (void) viewDidLoad { [super viewDidLoad]; //Setup additional views here. self.navigationItem.title = @"ROOT files"; self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle : @"Back to ROOT files" style : UIBarButtonItemStylePlain target : nil action : nil]; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle : @"Open file" style : UIBarButtonItemStylePlain target : self action : @selector(showFileOpenView)]; scrollView.bounces = NO; [self.view bringSubviewToFront : fileOpenView];//it's still hidden. fileNameField.clearButtonMode = UITextFieldViewModeAlways; UITapGestureRecognizer * const tap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector(hideFileOpenView)]; //Usual Apple's fu..up with gestures. tap.delegate = self; [self.view addGestureRecognizer : tap]; } //____________________________________________________________________________________________________ - (void) viewWillAppear : (BOOL)animated { [super viewWillAppear : animated]; [fileNameField resignFirstResponder];//? TODO: check why do I have this here at all. } //____________________________________________________________________________________________________ - (void) viewDidLayoutSubviews { //I only have to set correct positions for the shortcuts. [self correctFramesForOrientation : self.interfaceOrientation]; } //____________________________________________________________________________________________________ - (void) viewDidAppear : (BOOL) animated { [super viewDidAppear : animated]; if (!viewDidAppear) { //The first time this method is called, add the 'demos.root'. if (fileContainers.count) { for (UIView *shortcut in fileContainers) if (!shortcut.superview) [scrollView addSubview : shortcut]; [self correctFramesForOrientation : self.interfaceOrientation]; } viewDidAppear = YES; } } #pragma mark - View's geometry, interface orientation, etc. //____________________________________________________________________________________________________ - (void) placeFileShortcuts { using ROOT::iOS::Browser::PlaceShortcutsInScrollView; if ([scrollView.subviews count]) //25.f - is an additional 'pad' space between shortcuts. PlaceShortcutsInScrollView(fileContainers, scrollView, CGSizeMake([FileShortcutView iconWidth], [FileShortcutView iconHeight]), 25.f); } //____________________________________________________________________________________________________ - (void) correctFramesForOrientation : (UIInterfaceOrientation) orientation { #pragma unused(orientation) //This is the legacy code: before I was resetting views geometry manually, now no //need in this nightmare anymore, just place shortcuts in correct places. [self placeFileShortcuts]; } //____________________________________________________________________________________________________ - (BOOL) shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation) interfaceOrientation { #pragma unused(interfaceOrientation) return YES; } //____________________________________________________________________________________________________ - (void) willAnimateRotationToInterfaceOrientation : (UIInterfaceOrientation) interfaceOrientation duration : (NSTimeInterval) duration { #pragma unused(duration) [self correctFramesForOrientation : interfaceOrientation]; } #pragma mark - File shortcuts. //____________________________________________________________________________________________________ - (void) addRootFile : (NSString *) fileName { //Open the file and read its contents. assert(fileName != nil && "addRootFile:, parameter 'fileName' is nil"); using namespace ROOT::iOS::Browser; FileContainer * const fileContainer = FileContainer::CreateFileContainer([fileName cStringUsingEncoding : [NSString defaultCStringEncoding]]); if (!fileContainer) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle : @"File Open Error:" message : [NSString stringWithFormat:@"Could not open %@", fileName] delegate : nil cancelButtonTitle : @"Close" otherButtonTitles : nil]; [alert show]; return; } const CGRect shortcutFrame = CGRectMake(0.f, 0.f, [FileShortcutView iconWidth], [FileShortcutView iconHeight]); FileShortcutView * const newShortcut = [[FileShortcutView alloc] initWithFrame : shortcutFrame controller : self fileContainer : fileContainer]; if (newShortcut) { [fileContainers addObject : newShortcut]; if ([self isViewLoaded]) { [scrollView addSubview : newShortcut]; [self placeFileShortcuts]; }//else we'll do it later. } else FileContainer::DeleteFileContainer(fileContainer); } //____________________________________________________________________________________________________ - (void) fileWasSelected : (FileShortcutView *) shortcut { assert(shortcut != nil && "fileWasSelected:, parameter 'shortcut' is nil"); if (locked || fileNameField.isFirstResponder) return; assert(self.storyboard != nil && "fileWasSelected:, self.storyboard is nil"); UIViewController * const c = (UIViewController *)[self.storyboard instantiateViewControllerWithIdentifier : ROOT::iOS::Browser::FileContentViewControllerID]; assert([c isKindOfClass : [FileContentViewController class]] && "fileWasSelected:, file content view controller has a wrong type"); FileContentViewController * const contentController = (FileContentViewController *)c; [contentController activateForFile : [shortcut getFileContainer]]; [self.navigationController pushViewController : contentController animated : YES]; } //____________________________________________________________________________________________________ - (void) tryToDelete : (FileShortcutView *) shortcut { assert(shortcut != nil && "tryToDelete:, parameter 'shortcut' is nil"); if (locked || fileNameField.isFirstResponder) return; NSString * const message = [NSString stringWithFormat : @"Do you really want to close %@?", shortcut.fileName]; UIActionSheet * const dialog = [[UIActionSheet alloc] initWithTitle : message delegate : self cancelButtonTitle : @"Cancel" destructiveButtonTitle : @"Yes" otherButtonTitles : nil]; fileToDelete = shortcut; [dialog showInView : self.view]; } #pragma mark - Action sheet delegate, delete the file. //____________________________________________________________________________________________________ - (void) actionSheet : (UIActionSheet *) actionSheet didDismissWithButtonIndex : (NSInteger) buttonIndex { #pragma unused(actionSheet) if (!buttonIndex) { [fileContainers removeObject:fileToDelete]; [fileToDelete removeFromSuperview]; [self correctFramesForOrientation : self.interfaceOrientation]; } } #pragma mark - File open operations + text filed handling. //____________________________________________________________________________________________________ - (void) animateFileOpenView { assert(locked == NO && "animateFileOpenView, called while an animation is still active"); //Do animation. // First create a CATransition object to describe the transition CATransition * const transition = [CATransition animation]; transition.duration = 0.15; // using the ease in/out timing function transition.timingFunction = [CAMediaTimingFunction functionWithName : kCAMediaTimingFunctionEaseInEaseOut]; // Now to set the type of transition. transition.type = kCATransitionPush; if (!fileOpenView.hidden) transition.subtype = kCATransitionFromBottom; else transition.subtype = kCATransitionFromTop; transition.delegate = self; // Next add it to the containerView's layer. This will perform the transition based on how we change its contents. [fileOpenView.layer addAnimation : transition forKey : nil]; } //____________________________________________________________________________________________________ - (void) showFileOpenView { if (locked)//We're animating this view already. return; fileOpenView.hidden = !fileOpenView.hidden; [self animateFileOpenView]; if (!fileOpenView.hidden) [fileNameField becomeFirstResponder]; else [fileNameField resignFirstResponder]; } //____________________________________________________________________________________________________ - (IBAction) textFieldDidEndOnExit : (id) sender { #pragma unused(sender) NSString * const filePath = fileNameField.text; if (filePath) [self addRootFile : filePath]; } //____________________________________________________________________________________________________ - (IBAction) textFieldEditingDidEnd : (id) sender { #pragma unused(sender) [sender resignFirstResponder]; fileOpenView.hidden = YES; [self animateFileOpenView]; } //____________________________________________________________________________________________________ - (void) hideFileOpenView { [fileNameField resignFirstResponder]; fileOpenView.hidden = YES; [self animateFileOpenView]; } #pragma mark - CAAnimationDelegate. //____________________________________________________________________________________________________ - (void) animationDidStart : (CAAnimation *) anim { #pragma unused(anim) locked = YES; } //____________________________________________________________________________________________________ - (void) animationDidStop : (CAAnimation *) anim finished : (BOOL) flag { #pragma unused(anim) if (flag) locked = NO; } #pragma mark - Standard f..p with gestures. //____________________________________________________________________________________________________ - (BOOL) gestureRecognizer : (UIGestureRecognizer *) gestureRecognizer shouldReceiveTouch : (UITouch *) touch { #pragma unused(gestureRecognizer) if (locked) return NO; if ([touch.view isKindOfClass : [FileShortcutView class]]) return NO; return YES; } @end