1 #import "MasterViewController.h"
2 #import "EditViewController.h"
3 #import "DetailViewController.h"
4 #import "EditCancelAlert.h"
5 #import "NewFolderAlert.h"
9 #import "PasswordManager.h"
11 @interface MasterViewController () <UITableViewDelegate, UISplitViewControllerDelegate> {
12 NSMutableArray *_objects;
14 PasswordManager *passwordManager;
23 @implementation MasterViewController
25 @synthesize detailViewController = _detailViewController;
29 if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
30 self.clearsSelectionOnViewWillAppear = NO;
31 self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
39 // Do any additional setup after loading the view, typically from a nib.
40 self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
41 self.detailViewController.master = self;
42 self.splitViewController.delegate = self;
44 passwordManager = [[PasswordManager alloc] init];
46 UIBarButtonItem *newFolderBtn = [[UIBarButtonItem alloc] initWithTitle:@"New Folder"
47 style:UIBarButtonItemStyleBordered
49 action:@selector(createNewFolder:)];
50 [self setToolbarItems:[NSArray arrayWithObjects:newFolderBtn, nil] animated:YES];
51 [self.navigationController setToolbarHidden:NO];
56 storage = [Storage init];
59 // Load initial items.
65 [super viewDidUnload];
66 // Release any retained subviews of the main view.
70 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
72 if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
73 return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
80 - (void)openNewNote:(id)sender
82 if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
83 // iPhone : Transit to detail view.
84 [self performSegueWithIdentifier:@"newNote" sender:self];
86 // iPad : Clear detail view.
90 - (void)createNewFolder:(id)sender {
91 NewFolderAlert *alert = [[NewFolderAlert alloc] initWithDefault];
92 NSString *folderName = [alert showAndWait];
94 FileItem *item = [storage newFolder:folderName];
95 [self insertItem:item];
98 #pragma mark - Item operations
100 - (void)insertItems {
101 for (FileItem *file in [storage listItems]) {
102 [self insertItem: file];
104 if (!storage.isTopDir) {
105 FileItem *up = [FileItem allocWithName:@"UP"];
107 [self insertItem: up];
111 - (void)removeAllItems {
112 NSUInteger n = [_objects count];
114 NSMutableArray *rmItems = [[NSMutableArray alloc] initWithCapacity:n];
115 for (int i = 0; i < n; i++) {
116 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
117 [rmItems addObject: indexPath];
119 [_objects removeAllObjects];
120 [self.tableView deleteRowsAtIndexPaths: rmItems withRowAnimation:UITableViewRowAnimationAutomatic];
123 - (void)insertItem:(FileItem *)item {
125 _objects = [[NSMutableArray alloc] init];
127 NSUInteger n = [_objects count];
129 for (i = 0; i < n; i++) {
130 if (item.isUp) break;
132 FileItem *cur = [_objects objectAtIndex:i];
133 NSComparisonResult r = [item compare:cur];
134 if (r == NSOrderedAscending || r == NSOrderedSame) {
139 [_objects insertObject:item atIndex:i];
140 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
141 [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
142 withRowAnimation:UITableViewRowAnimationAutomatic];
145 - (void) deleteItem:(FileItem *)item {
147 for (FileItem *f in _objects) {
148 if ([f.name isEqualToString: item.name]) {
149 [_objects removeObjectAtIndex:i];
150 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
151 [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
152 withRowAnimation:UITableViewRowAnimationAutomatic];
159 - (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation {
163 #pragma mark - Table View
165 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
170 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
172 return _objects.count;
175 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
177 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
179 FileItem *fItem = [_objects objectAtIndex:indexPath.row];
180 cell.textLabel.text = [fItem name];
183 imgUp = [UIImage imageNamed:@"sub_blue_up-32"];
185 cell.imageView.image = imgUp;
186 } else if (fItem.isCrypt) {
188 imgKey = [UIImage imageNamed:@"key-32"];
190 cell.imageView.image = imgKey;
191 } else if (fItem.isDirectory) {
193 imgFolder = [UIImage imageNamed:@"Folder-32"];
196 cell.imageView.image = imgFolder;
199 imgDocument = [UIImage imageNamed:@"TextDocument-32"];
201 cell.imageView.image = imgDocument;
206 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
208 // Return NO if you do not want the specified item to be editable.
209 FileItem *item = [_objects objectAtIndex:indexPath.row];
210 if (item.isUp) return NO;
214 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
216 if (editingStyle == UITableViewCellEditingStyleDelete) {
217 FileItem *item = [_objects objectAtIndex:indexPath.row];
218 [storage deleteItem:item];
220 [_objects removeObjectAtIndex:indexPath.row];
221 [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
222 withRowAnimation:UITableViewRowAnimationFade];
223 } else if (editingStyle == UITableViewCellEditingStyleInsert) {
224 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
229 // Override to support rearranging the table view.
230 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
236 // Override to support conditional rearranging of the table view.
237 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
239 // Return NO if you do not want the item to be re-orderable.
244 - (void)transitToDetailView:(FileItem *)item {
245 if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
246 self.detailViewController.item = item;
248 [self performSegueWithIdentifier:@"showNote" sender:self];
252 // Select Row(iPhone/iPad)
254 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
256 FileItem *item = [_objects objectAtIndex:indexPath.row];
259 [self removeAllItems];
262 } else if (item.isDirectory) {
263 [self removeAllItems];
264 [storage chdir: item.name];
268 if ([passwordManager preparePassword]) {
269 // Check to success decrypt and transit.
270 NSString *note = [Storage loadCryptFile:item.path password:passwordManager.password];
272 [self transitToDetailView:item];
274 UIAlertView *decryptFail = [[UIAlertView alloc] initWithTitle:@"Error"
275 message:@"Decryption failed."
277 cancelButtonTitle:@"OK"
278 otherButtonTitles:nil];
280 // Invalid password so clear it.
281 passwordManager.password = nil;
285 [self transitToDetailView:item];
290 // set item (for iPhone)
291 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
293 if ([[segue identifier] isEqualToString:@"newNote"]) {
294 EditViewController *edit = (EditViewController*)[[[segue destinationViewController] viewControllers] objectAtIndex:0];
295 edit.detailItem = [storage newItem];
296 edit.delegate = self;
297 } else if ([[segue identifier] isEqualToString:@"editNote"]) {
298 // This path is used only iPhone
299 EditViewController *edit = (EditViewController*)[[[segue destinationViewController] viewControllers] objectAtIndex:0];
300 NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
301 FileItem *item = [_objects objectAtIndex:indexPath.row];
302 edit.detailItem = item;
303 edit.delegate = self;
304 } else if ([[segue identifier] isEqualToString:@"showNote"]) {
305 DetailViewController *detail = [segue destinationViewController];
306 self.detailViewController = detail;
307 NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
308 FileItem *item = [_objects objectAtIndex:indexPath.row];
310 detail.storage = storage;
311 detail.passwordManager = passwordManager;
312 detail.master = self;
313 detail.delegate = self;
317 #pragma mark - EditViewControllerDelegate
319 - (void)editViewControllerDidFinish:(EditViewController *)controller {
320 if (controller.isModify) {
322 if (![controller.detailItem isNewItem]) {
323 [self deleteItem:controller.detailItem];
325 NSString *note = controller.detailText.text;
327 if (controller.detailItem.isCrypt) {
328 if ([passwordManager preparePasswordConfirm]) {
329 item = [storage saveCrypt:note item:controller.detailItem password:passwordManager.password];
331 // Don't dismiss view.
335 item = [storage savePlain:note item:controller.detailItem];
337 controller.isModify = NO;
339 self.detailViewController.item = item;
341 [self insertItem:item];
343 [self dismissModalViewControllerAnimated:YES];
346 - (void)editViewControllerDidCancel:(EditViewController *)controller {
347 if (controller.isModify) {
348 EditCancelAlert *cancel = [[EditCancelAlert alloc] initWithDefault];
349 if ([cancel showAndWait]) {
350 [self dismissModalViewControllerAnimated:YES];
353 [self dismissModalViewControllerAnimated:YES];
357 #pragma mark - DetailViewDelegate
359 -(void)detailViewFileItemChanged:(FileItem*)oldItem to:(FileItem *)newItem {
360 [self deleteItem:oldItem];
361 [self insertItem:newItem];