2016-05-11 21:04:49 +00:00
//
// InsertDiskViewController . m
// Mini vMac
//
// Created by Jes ú s A . Á lvarez on 07 / 05 / 2016.
// Copyright © 2016 namedfork . All rights reserved .
//
# import "InsertDiskViewController.h"
# import "AppDelegate.h"
2016-05-21 13:01:57 +00:00
# import "UIImage+DiskImageIcon.h"
2016-05-11 21:04:49 +00:00
2016-06-03 21:33:26 +00:00
@ interface InsertDiskViewController ( ) < UITextFieldDelegate , UIAlertViewDelegate >
2016-05-11 21:04:49 +00:00
@ end
@ interface FileTableViewCell : UITableViewCell
@ property ( nonatomic , weak ) InsertDiskViewController * controller ;
@ property ( nonatomic , strong ) NSString * filePath ;
2016-06-04 13:13:08 +00:00
@ property ( nonatomic , assign ) BOOL showExtension ;
2016-05-11 21:04:49 +00:00
- ( void ) share : ( id ) sender ;
- ( void ) rename : ( id ) sender ;
- ( void ) delete : ( id ) sender ;
@ end
@ implementation InsertDiskViewController
{
NSString * basePath ;
NSArray < NSString * > * diskImages , * otherFiles ;
UIAlertController * createDiskImageController ;
2016-06-06 16:25:30 +00:00
UIAlertView * createDiskImageAlert ;
2016-05-11 21:04:49 +00:00
__block __weak UITextField * sizeTextField ;
__block __weak UITextField * nameTextField ;
2016-06-03 21:33:26 +00:00
NSString * fileToRename ;
2016-06-04 13:13:08 +00:00
BOOL importing ;
2016-05-11 21:04:49 +00:00
}
+ ( void ) initialize {
UIMenuController * menuController = [ UIMenuController sharedMenuController ] ;
menuController . menuItems = @ [ [ [ UIMenuItem alloc ] initWithTitle : NSLocalizedString ( @ "Rename" , @ "Rename Context Menu Item" ) action : @ selector ( rename : ) ] ,
[ [ UIMenuItem alloc ] initWithTitle : NSLocalizedString ( @ "Share" , @ "Share Context Menu Item" ) action : @ selector ( share : ) ] ] ;
}
- ( void ) viewDidLoad {
[ super viewDidLoad ] ;
basePath = [ AppDelegate sharedInstance ] . documentsPath ;
[ self loadDirectoryContents ] ;
self . navigationItem . rightBarButtonItem = self . editButtonItem ;
}
2016-06-04 13:13:08 +00:00
- ( void ) viewWillAppear : ( BOOL ) animated {
[ super viewWillAppear : animated ] ;
importing = [ [ AppDelegate sharedEmulator ] . currentApplication isEqualToString : @ "ImportFl" ] ;
if ( importing ) {
self . title = NSLocalizedString ( @ "Import File" , nil ) ;
}
}
2016-05-11 21:04:49 +00:00
- ( void ) viewDidAppear : ( BOOL ) animated {
[ super viewDidAppear : animated ] ;
NSNotificationCenter * nc = [ NSNotificationCenter defaultCenter ] ;
2016-05-28 11:01:13 +00:00
[ nc addObserver : self selector : @ selector ( reloadData : ) name : [ AppDelegate sharedEmulator ] . insertDiskNotification object : nil ] ;
[ nc addObserver : self selector : @ selector ( reloadData : ) name : [ AppDelegate sharedEmulator ] . ejectDiskNotification object : nil ] ;
2016-06-06 17:42:10 +00:00
[ nc addObserver : self selector : @ selector ( reloadData : ) name : DocumentsChangedNotification object : nil ] ;
2016-05-11 21:04:49 +00:00
}
- ( void ) viewDidDisappear : ( BOOL ) animated {
[ super viewDidDisappear : animated ] ;
NSNotificationCenter * nc = [ NSNotificationCenter defaultCenter ] ;
2016-05-28 11:01:13 +00:00
[ nc removeObserver : self name : [ AppDelegate sharedEmulator ] . insertDiskNotification object : nil ] ;
[ nc removeObserver : self name : [ AppDelegate sharedEmulator ] . ejectDiskNotification object : nil ] ;
2016-06-06 17:42:10 +00:00
[ nc removeObserver : self name : DocumentsChangedNotification object : nil ] ;
2016-05-11 21:04:49 +00:00
}
- ( void ) loadDirectoryContents {
NSArray * allFiles = [ [ NSFileManager defaultManager ] contentsOfDirectoryAtPath : basePath error : NULL ] ;
2016-05-26 19:07:54 +00:00
diskImages = [ allFiles filteredArrayUsingPredicate : [ NSPredicate predicateWithFormat : @ "%@ containsObject: pathExtension.lowercaseString" , [ AppDelegate sharedInstance ] . diskImageExtensions ] ] ;
2016-05-11 21:04:49 +00:00
otherFiles = [ allFiles filteredArrayUsingPredicate : [ NSPredicate predicateWithBlock : ^ BOOL ( NSString * _Nonnull name , NSDictionary < NSString * , id > * _Nullable bindings ) {
BOOL isDiskImage = [ diskImages containsObject : name ] ;
BOOL isDirectory ;
BOOL isHidden = [ name hasPrefix : @ "." ] ;
[ [ NSFileManager defaultManager ] fileExistsAtPath : [ basePath stringByAppendingPathComponent : name ] isDirectory : & isDirectory ] ;
return ! ( isDirectory || isDiskImage || isHidden ) ;
} ] ] ;
}
- ( void ) reloadData : ( id ) sender {
[ self loadDirectoryContents ] ;
[ self . tableView reloadData ] ;
}
2016-06-06 16:57:42 +00:00
- ( IBAction ) refresh : ( id ) sender {
[ self reloadData : sender ] ;
[ self . refreshControl endRefreshing ] ;
}
2016-05-25 18:49:56 +00:00
# pragma mark - Button Actions
2016-05-11 21:04:49 +00:00
- ( void ) showSettings : ( id ) sender {
[ [ AppDelegate sharedInstance ] showSettings : sender ] ;
}
- ( void ) dismiss : ( id ) sender {
[ self dismissViewControllerAnimated : YES completion : nil ] ;
}
2016-05-25 18:49:56 +00:00
- ( void ) macInterrupt : ( id ) sender {
[ self dismiss : sender ] ;
2016-05-28 11:01:13 +00:00
[ [ AppDelegate sharedEmulator ] interrupt ] ;
2016-05-25 18:49:56 +00:00
}
- ( void ) macReset : ( id ) sender {
2016-05-28 11:01:13 +00:00
[ [ AppDelegate sharedEmulator ] reset ] ;
2016-05-25 18:49:56 +00:00
}
2016-05-11 21:04:49 +00:00
# pragma mark - Table view data source
- ( NSInteger ) numberOfSectionsInTableView : ( UITableView * ) tableView {
2016-06-04 13:13:08 +00:00
return self . editing || importing ? 2 : 1 ;
2016-05-11 21:04:49 +00:00
}
- ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section {
switch ( section ) {
2016-06-06 16:25:30 +00:00
case 0 : return diskImages . count + ( self . editing ? 1 : 0 ) ;
2016-05-11 21:04:49 +00:00
case 1 : return otherFiles . count ;
default : return 0 ;
}
}
- ( NSString * ) tableView : ( UITableView * ) tableView titleForHeaderInSection : ( NSInteger ) section {
return section = = 0 ? NSLocalizedString ( @ "Disk Images" , nil ) : NSLocalizedString ( @ "Other Files" , nil ) ;
}
- ( CGFloat ) tableView : ( UITableView * ) tableView heightForHeaderInSection : ( NSInteger ) section {
return self . editing ? UITableViewAutomaticDimension : 0.0 ;
}
- ( void ) setEditing : ( BOOL ) editing animated : ( BOOL ) animated {
[ super setEditing : editing animated : animated ] ;
[ self . tableView beginUpdates ] ;
[ self loadDirectoryContents ] ;
self . tableView . tableHeaderView = nil ;
[ self . tableView reloadSections : [ NSIndexSet indexSetWithIndex : 0 ] withRowAnimation : UITableViewRowAnimationFade ] ;
2016-06-04 13:28:47 +00:00
if ( importing ) {
[ self . tableView reloadSections : [ NSIndexSet indexSetWithIndex : 1 ] withRowAnimation : UITableViewRowAnimationFade ] ;
} else if ( editing ) {
2016-05-11 21:04:49 +00:00
[ self . tableView insertSections : [ NSIndexSet indexSetWithIndex : 1 ] withRowAnimation : UITableViewRowAnimationFade ] ;
} else {
[ self . tableView deleteSections : [ NSIndexSet indexSetWithIndex : 1 ] withRowAnimation : UITableViewRowAnimationFade ] ;
}
[ self . tableView endUpdates ] ;
}
- ( NSString * ) fileAtIndexPath : ( NSIndexPath * ) indexPath {
NSArray < NSString * > * files = indexPath . section = = 0 ? diskImages : otherFiles ;
if ( indexPath . row < files . count ) {
NSString * fileName = files [ indexPath . row ] ;
return [ basePath stringByAppendingPathComponent : fileName ] ;
} else {
return nil ;
}
}
- ( NSIndexPath * ) indexPathForFile : ( NSString * ) filePath {
NSString * fileName = filePath . lastPathComponent ;
if ( [ diskImages containsObject : fileName ] ) {
return [ NSIndexPath indexPathForRow : [ diskImages indexOfObject : fileName ] inSection : 0 ] ;
} else if ( [ otherFiles containsObject : fileName ] ) {
return [ NSIndexPath indexPathForRow : [ otherFiles indexOfObject : fileName ] inSection : 1 ] ;
} else {
return nil ;
}
}
- ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath {
FileTableViewCell * cell = [ tableView dequeueReusableCellWithIdentifier : @ "cell" forIndexPath : indexPath ] ;
NSString * filePath = [ self fileAtIndexPath : indexPath ] ;
if ( filePath ) {
2016-06-04 13:13:08 +00:00
cell . showExtension = self . editing || importing ;
2016-05-11 21:04:49 +00:00
cell . filePath = filePath ;
2016-05-28 11:01:13 +00:00
if ( [ [ AppDelegate sharedEmulator ] isDiskInserted : filePath ] ) {
2016-05-11 21:04:49 +00:00
cell . userInteractionEnabled = NO ;
cell . textLabel . enabled = NO ;
cell . imageView . alpha = 0.5 ;
}
} else {
cell . textLabel . text = NSLocalizedString ( @ "Create Disk Image…" , nil ) ;
cell . detailTextLabel . text = nil ;
}
cell . controller = self ;
return cell ;
}
- ( UITableViewCellEditingStyle ) tableView : ( UITableView * ) tableView editingStyleForRowAtIndexPath : ( NSIndexPath * ) indexPath {
if ( self . editing = = NO ) {
return UITableViewCellEditingStyleNone ;
} else if ( indexPath . section = = 0 ) {
if ( indexPath . row = = diskImages . count ) {
return UITableViewCellEditingStyleInsert ;
}
NSString * filePath = [ self fileAtIndexPath : indexPath ] ;
2016-05-28 11:01:13 +00:00
BOOL isInserted = [ [ AppDelegate sharedEmulator ] isDiskInserted : filePath ] ;
2016-05-11 21:04:49 +00:00
return isInserted ? UITableViewCellEditingStyleNone : UITableViewCellEditingStyleDelete ;
} else {
return UITableViewCellEditingStyleDelete ;
}
}
- ( void ) tableView : ( UITableView * ) tableView commitEditingStyle : ( UITableViewCellEditingStyle ) editingStyle forRowAtIndexPath : ( NSIndexPath * ) indexPath {
if ( editingStyle = = UITableViewCellEditingStyleDelete ) {
2016-05-26 21:23:49 +00:00
NSString * filePath = [ self fileAtIndexPath : indexPath ] ;
if ( [ UIAlertController class ] ) {
[ self askDeleteFile : filePath ] ;
} else {
[ self deleteFile : filePath ] ;
}
2016-05-11 21:04:49 +00:00
} else if ( editingStyle = = UITableViewCellEditingStyleInsert ) {
[ self createDiskImage ] ;
}
}
- ( BOOL ) tableView : ( UITableView * ) tableView shouldShowMenuForRowAtIndexPath : ( nonnull NSIndexPath * ) indexPath {
return [ self fileAtIndexPath : indexPath ] ! = nil ;
}
- ( BOOL ) tableView : ( UITableView * ) tableView canPerformAction : ( SEL ) action forRowAtIndexPath : ( NSIndexPath * ) indexPath withSender : ( id ) sender {
2016-06-03 21:33:26 +00:00
return ( action = = @ selector ( share : ) || ( action = = @ selector ( rename : ) || ( [ UIAlertController class ] && action = = @ selector ( delete : ) ) ) ) ;
2016-05-11 21:04:49 +00:00
}
- ( void ) tableView : ( UITableView * ) tableView performAction : ( SEL ) action forRowAtIndexPath : ( NSIndexPath * ) indexPath withSender : ( id ) sender {
// menu will not be shown if this method doesn ' t exist
}
- ( void ) tableView : ( UITableView * ) tableView didSelectRowAtIndexPath : ( NSIndexPath * ) indexPath {
NSString * filePath = [ self fileAtIndexPath : indexPath ] ;
2016-05-28 11:01:13 +00:00
if ( filePath && ! [ [ AppDelegate sharedEmulator ] isDiskInserted : filePath ] ) {
2016-05-11 21:04:49 +00:00
[ self dismissViewControllerAnimated : YES completion : ^ {
2016-05-28 11:01:13 +00:00
[ [ AppDelegate sharedEmulator ] insertDisk : filePath ] ;
2016-05-11 21:04:49 +00:00
} ] ;
}
}
# pragma mark - File Actions
2016-05-26 21:23:49 +00:00
- ( void ) deleteFile : ( NSString * ) filePath {
NSError * error = nil ;
if ( [ [ NSFileManager defaultManager ] removeItemAtPath : filePath error : & error ] ) {
NSIndexPath * indexPath = [ self indexPathForFile : filePath ] ;
[ self loadDirectoryContents ] ;
[ self . tableView deleteRowsAtIndexPaths : @ [ indexPath ] withRowAnimation : UITableViewRowAnimationFade ] ;
} else {
[ [ AppDelegate sharedInstance ] showAlertWithTitle : NSLocalizedString ( @ "Could not delete file" , nil ) message : error . localizedDescription ] ;
}
}
2016-05-11 21:04:49 +00:00
- ( void ) askDeleteFile : ( NSString * ) filePath {
NSString * fileName = filePath . lastPathComponent ;
NSString * message = [ NSString stringWithFormat : NSLocalizedString ( @ "Are you sure you want to delete %@? This operation cannot be undone." , nil ) , fileName ] ;
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : NSLocalizedString ( @ "Delete File" , nil ) message : message preferredStyle : UIAlertControllerStyleAlert ] ;
2016-06-04 10:36:36 +00:00
[ alertController addAction : [ UIAlertAction actionWithTitle : NSLocalizedString ( @ "Cancel" , nil ) style : UIAlertActionStyleCancel handler : nil ] ] ;
2016-05-11 21:04:49 +00:00
[ alertController addAction : [ UIAlertAction actionWithTitle : NSLocalizedString ( @ "Delete" , nil ) style : UIAlertActionStyleDestructive handler : ^ ( UIAlertAction * _Nonnull action ) {
2016-05-26 21:23:49 +00:00
[ self deleteFile : filePath ] ;
2016-05-11 21:04:49 +00:00
} ] ] ;
[ self presentViewController : alertController animated : YES completion : nil ] ;
}
- ( void ) askRenameFile : ( NSString * ) filePath {
NSString * fileName = filePath . lastPathComponent ;
2016-06-03 21:33:26 +00:00
if ( [ UIAlertController class ] ) {
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : fileName message : NSLocalizedString ( @ "Enter new name" , nil ) preferredStyle : UIAlertControllerStyleAlert ] ;
[ alertController addTextFieldWithConfigurationHandler : ^ ( UITextField * _Nonnull textField ) {
nameTextField = textField ;
textField . delegate = self ;
textField . placeholder = fileName ;
textField . text = fileName ;
} ] ;
2016-06-04 10:36:36 +00:00
[ alertController addAction : [ UIAlertAction actionWithTitle : NSLocalizedString ( @ "Cancel" , nil ) style : UIAlertActionStyleCancel handler : nil ] ] ;
2016-06-03 21:33:26 +00:00
[ alertController addAction : [ UIAlertAction actionWithTitle : NSLocalizedString ( @ "Rename" , nil ) style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * _Nonnull action ) {
NSString * newName = alertController . textFields . firstObject . text ;
[ self renameFile : filePath toName : newName ] ;
} ] ] ;
[ self presentViewController : alertController animated : YES completion : nil ] ;
} else {
UIAlertView * alertView = [ [ UIAlertView alloc ] initWithTitle : fileName message : NSLocalizedString ( @ "Enter new name" , nil ) delegate : self cancelButtonTitle : NSLocalizedString ( @ "Cancel" , nil ) otherButtonTitles : NSLocalizedString ( @ "Rename" , nil ) , nil ] ;
alertView . alertViewStyle = UIAlertViewStylePlainTextInput ;
nameTextField = [ alertView textFieldAtIndex : 0 ] ;
nameTextField . delegate = self ;
nameTextField . placeholder = fileName ;
nameTextField . text = fileName ;
fileToRename = filePath ;
[ alertView show ] ;
}
}
- ( void ) renameFile : ( NSString * ) filePath toName : ( NSString * ) newName {
NSError * error = nil ;
NSString * newPath = [ filePath . stringByDeletingLastPathComponent stringByAppendingPathComponent : newName ] ;
if ( [ [ NSFileManager defaultManager ] moveItemAtPath : filePath toPath : newPath error : & error ] ) {
NSIndexPath * oldIndexPath = [ self indexPathForFile : filePath ] ;
[ self loadDirectoryContents ] ;
NSIndexPath * newIndexPath = [ self indexPathForFile : newPath ] ;
if ( newIndexPath = = nil || newIndexPath . section >= self . tableView . numberOfSections ) {
[ self . tableView deleteRowsAtIndexPaths : @ [ oldIndexPath ] withRowAnimation : UITableViewRowAnimationFade ] ;
2016-05-11 21:04:49 +00:00
} else {
2016-06-03 21:33:26 +00:00
[ self . tableView moveRowAtIndexPath : oldIndexPath toIndexPath : newIndexPath ] ;
[ self . tableView reloadRowsAtIndexPaths : @ [ newIndexPath ] withRowAnimation : UITableViewRowAnimationNone ] ;
2016-05-11 21:04:49 +00:00
}
2016-06-03 21:33:26 +00:00
} else {
[ [ AppDelegate sharedInstance ] showAlertWithTitle : NSLocalizedString ( @ "Could not rename file" , nil ) message : error . localizedDescription ] ;
}
2016-05-11 21:04:49 +00:00
}
# pragma mark - Disk Image Creation
- ( void ) createDiskImage {
2016-06-06 16:25:30 +00:00
if ( [ UIAlertController class ] ) {
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : NSLocalizedString ( @ "Create Disk Image" , nil ) message : nil preferredStyle : UIAlertControllerStyleAlert ] ;
[ alertController addTextFieldWithConfigurationHandler : ^ ( UITextField * _Nonnull textField ) {
textField . placeholder = NSLocalizedString ( @ "name" , nil ) ;
[ textField addTarget : self action : @ selector ( validateCreateDiskImageInput : ) forControlEvents : UIControlEventAllEditingEvents ] ;
2016-05-11 21:04:49 +00:00
} ] ;
2016-06-06 16:25:30 +00:00
[ alertController addTextFieldWithConfigurationHandler : ^ ( UITextField * _Nonnull textField ) {
[ self _configureNewDiskSizeField : textField ] ;
} ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : NSLocalizedString ( @ "Cancel" , nil ) style : UIAlertActionStyleCancel handler : nil ] ] ;
UIAlertAction * createAction = [ UIAlertAction actionWithTitle : NSLocalizedString ( @ "Create" , nil ) style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * _Nonnull action ) {
NSString * name = [ self _newDiskImageName ] ;
off_t size = [ self _newDiskImageSize ] ;
createDiskImageController = nil ;
[ self createDiskImageWithName : name size : size ] ;
} ] ;
[ alertController addAction : createAction ] ;
createAction . enabled = NO ;
[ self presentViewController : alertController animated : YES completion : nil ] ;
createDiskImageController = alertController ;
} else {
UIAlertView * alertView = [ [ UIAlertView alloc ] initWithTitle : NSLocalizedString ( @ "Create Disk Image" , nil ) message : nil delegate : self cancelButtonTitle : NSLocalizedString ( @ "Cancel" , nil ) otherButtonTitles : NSLocalizedString ( @ "Create" , nil ) , nil ] ;
alertView . alertViewStyle = UIAlertViewStyleLoginAndPasswordInput ;
nameTextField = [ alertView textFieldAtIndex : 0 ] ;
nameTextField . delegate = self ;
nameTextField . placeholder = NSLocalizedString ( @ "name" , nil ) ;
[ nameTextField addTarget : self action : @ selector ( validateCreateDiskImageInput : ) forControlEvents : UIControlEventAllEditingEvents ] ;
[ self _configureNewDiskSizeField : [ alertView textFieldAtIndex : 1 ] ] ;
createDiskImageAlert = alertView ;
[ alertView show ] ;
}
}
- ( void ) _configureNewDiskSizeField : ( UITextField * ) textField {
textField . secureTextEntry = NO ;
textField . placeholder = NSLocalizedString ( @ "size" , nil ) ;
textField . keyboardType = UIKeyboardTypeDecimalPad ;
UILabel * unitLabel = [ [ UILabel alloc ] initWithFrame : CGRectMake ( 0 , 0 , 60.0 , 32.0 ) ] ;
textField . rightViewMode = UITextFieldViewModeAlways ;
textField . rightView = unitLabel ;
unitLabel . textAlignment = NSTextAlignmentRight ;
UISegmentedControl * unitsControl = [ [ UISegmentedControl alloc ] initWithFrame : CGRectMake ( 0 , 0 , 80.0 , 16.0 ) ] ;
NSArray * units = @ [ NSLocalizedString ( @ "KB" , nil ) , NSLocalizedString ( @ "MB" , nil ) ] ;
[ units enumerateObjectsUsingBlock : ^ ( NSString * title , NSUInteger idx , BOOL * _Nonnull stop ) {
[ unitsControl insertSegmentWithTitle : title atIndex : idx animated : NO ] ;
2016-05-11 21:04:49 +00:00
} ] ;
2016-06-06 16:25:30 +00:00
unitsControl . selectedSegmentIndex = 0 ;
textField . rightView = unitsControl ;
sizeTextField = textField ;
textField . delegate = self ;
[ textField addTarget : self action : @ selector ( validateCreateDiskImageInput : ) forControlEvents : UIControlEventAllEditingEvents ] ;
[ unitsControl addTarget : self action : @ selector ( validateCreateDiskImageInput : ) forControlEvents : UIControlEventValueChanged ] ;
unitLabel . text = [ unitsControl titleForSegmentAtIndex : unitsControl . selectedSegmentIndex ] ;
2016-05-11 21:04:49 +00:00
}
- ( BOOL ) validateCreateDiskImageInput : ( id ) sender {
BOOL valid = NO ;
2016-06-06 16:25:30 +00:00
if ( self . presentedViewController = = createDiskImageController || createDiskImageAlert . visible ) {
2016-05-11 21:04:49 +00:00
NSString * name = [ self _newDiskImageName ] ;
BOOL nameIsValid = ( name . length > 0 ) && ! [ name hasPrefix : @ "." ] && ! [ name containsString : @ "/" ] && ! [ name containsString : @ "*" ] ;
off_t size = [ self _newDiskImageSize ] ;
BOOL sizeIsValid = ( size >= 400 * 1024 ) && ( size <= 2 LL * 1024 * 1024 * 1024 ) ;
valid = nameIsValid && sizeIsValid ;
2016-06-06 16:25:30 +00:00
if ( createDiskImageController ! = nil ) {
UIAlertAction * createAction = createDiskImageController . actions [ 1 ] ;
createAction . enabled = valid ;
} else if ( sender = = sizeTextField . rightView ) {
// fake edit event to call alertViewShouldEnableFirstOtherButton
[ sizeTextField sendActionsForControlEvents : UIControlEventEditingChanged ] ;
}
2016-05-11 21:04:49 +00:00
}
return valid ;
}
- ( NSString * ) _newDiskImageName {
2016-06-06 16:25:30 +00:00
if ( createDiskImageController ! = nil ) {
return createDiskImageController . textFields [ 0 ] . text ;
} else if ( createDiskImageAlert . visible ) {
return nameTextField . text ;
} else {
return nil ;
}
2016-05-11 21:04:49 +00:00
}
- ( off_t ) _newDiskImageSize {
2016-06-06 16:25:30 +00:00
if ( createDiskImageController = = nil && ! createDiskImageAlert . visible ) {
2016-05-11 21:04:49 +00:00
return 0 ;
}
2016-06-06 16:25:30 +00:00
UISegmentedControl * unitsControl = ( UISegmentedControl * ) sizeTextField . rightView ;
2016-05-11 21:04:49 +00:00
off_t unitsMultiplier = ( unitsControl . selectedSegmentIndex = = 0 ) ? 1024 : 1024 * 1024 ;
2016-06-06 16:25:30 +00:00
off_t size = sizeTextField . text . floatValue * unitsMultiplier ;
2016-05-11 21:04:49 +00:00
return size ;
}
- ( void ) createDiskImageWithName : ( NSString * ) name size : ( off_t ) size {
NSString * imageFileName = [ [ AppDelegate sharedInstance ] . diskImageExtensions containsObject : name . pathExtension . lowercaseString ] ? name : [ name stringByAppendingPathExtension : @ "img" ] ;
NSString * imagePath = [ basePath stringByAppendingPathComponent : imageFileName ] ;
int fd = open ( imagePath . fileSystemRepresentation , O_CREAT | O_TRUNC | O_EXCL | O_WRONLY , 0666 ) ;
if ( fd = = -1 ) {
[ [ AppDelegate sharedInstance ] showAlertWithTitle : NSLocalizedString ( @ "Could not create disk image" , nil ) message : [ [ NSString alloc ] initWithUTF8String : strerror ( errno ) ] ] ;
return ;
}
2016-06-06 18:49:48 +00:00
UIActivityIndicatorView * activityIndicatorView = [ [ UIActivityIndicatorView alloc ] initWithActivityIndicatorStyle : UIActivityIndicatorViewStyleWhiteLarge ] ;
activityIndicatorView . color = [ UIColor blackColor ] ;
if ( [ UIAlertController class ] ) {
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : NSLocalizedString ( @ "Creating Disk Image" , nil ) message : @ "\n\n\n" preferredStyle : UIAlertControllerStyleAlert ] ;
[ self presentViewController : alertController animated : true completion : ^ {
UIView * alertView = alertController . view ;
activityIndicatorView . autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin ;
activityIndicatorView . center = CGPointMake ( alertView . bounds . size . width / 2.0 , alertView . bounds . size . height / 2.0 + 32.0 ) ;
[ alertView addSubview : activityIndicatorView ] ;
[ activityIndicatorView startAnimating ] ;
[ self _writeNewDiskImage : fd size : size activityIndicator : activityIndicatorView progressAlert : alertController ] ;
} ] ;
} else {
UIAlertView * alertView = [ [ UIAlertView alloc ] initWithTitle : NSLocalizedString ( @ "Creating Disk Image" , nil ) message : nil delegate : nil cancelButtonTitle : nil otherButtonTitles : nil ] ;
[ alertView addSubview : activityIndicatorView ] ;
[ activityIndicatorView startAnimating ] ;
[ alertView setValue : activityIndicatorView forKey : @ "accessoryView" ] ;
[ alertView show ] ;
[ self _writeNewDiskImage : fd size : size activityIndicator : activityIndicatorView progressAlert : alertView ] ;
}
}
- ( void ) _writeNewDiskImage : ( int ) fd size : ( off_t ) size activityIndicator : ( UIActivityIndicatorView * ) activityIndicatorView progressAlert : ( id ) progressAlert {
long queue = NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS _8 _0 ? QOS_CLASS _USER _INITIATED : DISPATCH_QUEUE _PRIORITY _HIGH ;
dispatch_async ( dispatch_get _global _queue ( queue , 0 ) , ^ {
int error = 0 ;
if ( ftruncate ( fd , size ) ) {
error = errno ;
}
close ( fd ) ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ activityIndicatorView stopAnimating ] ;
if ( [ progressAlert isKindOfClass : [ UIAlertController class ] ] ) {
2016-05-11 21:04:49 +00:00
[ self dismissViewControllerAnimated : YES completion : ^ {
if ( error ) {
[ [ AppDelegate sharedInstance ] showAlertWithTitle : NSLocalizedString ( @ "Could not create disk image" , nil ) message : [ [ NSString alloc ] initWithUTF8String : strerror ( error ) ] ] ;
}
} ] ;
2016-06-06 18:49:48 +00:00
} else if ( [ progressAlert isKindOfClass : [ UIAlertView class ] ] ) {
UIAlertView * alert = progressAlert ;
[ alert dismissWithClickedButtonIndex : 0 animated : NO ] ;
if ( error ) {
[ [ AppDelegate sharedInstance ] showAlertWithTitle : NSLocalizedString ( @ "Could not create disk image" , nil ) message : [ [ NSString alloc ] initWithUTF8String : strerror ( error ) ] ] ;
}
}
[ self . tableView beginUpdates ] ;
[ self loadDirectoryContents ] ;
[ self . tableView reloadSections : [ NSIndexSet indexSetWithIndex : 0 ] withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . tableView endUpdates ] ;
2016-05-11 21:04:49 +00:00
} ) ;
2016-06-06 18:49:48 +00:00
} ) ;
2016-05-11 21:04:49 +00:00
}
# pragma mark - Text Field Delegate
- ( BOOL ) textField : ( UITextField * ) textField shouldChangeCharactersInRange : ( NSRange ) range replacementString : ( NSString * ) string {
if ( textField = = sizeTextField ) {
UISegmentedControl * unitsControl = ( UISegmentedControl * ) textField . rightView ;
NSArray * unitShortcuts = @ [ @ "k" , @ "m" ] ;
if ( string . length = = 0 ) {
return YES ;
} else if ( string . length = = 1 && [ unitShortcuts indexOfObject : string . lowercaseString ] ! = NSNotFound ) {
unitsControl . selectedSegmentIndex = [ unitShortcuts indexOfObject : string . lowercaseString ] ;
[ unitsControl sendActionsForControlEvents : UIControlEventValueChanged ] ;
return NO ;
} else {
NSString * newString = [ textField . text stringByReplacingCharactersInRange : range withString : string ] ;
NSScanner * scanner = [ NSScanner scannerWithString : newString ] ;
double value ;
return [ scanner scanDouble : & value ] && scanner . isAtEnd && value >= 0 ;
}
} else {
return YES ;
}
}
- ( void ) textFieldDidBeginEditing : ( UITextField * ) textField {
if ( textField = = nameTextField && textField . text . pathExtension . length > 0 ) {
UITextPosition * beforeExtensionPosition = [ textField positionFromPosition : textField . endOfDocument offset : - ( textField . text . pathExtension . length + 1 ) ] ;
UITextRange * nameWithoutExtensionRange = [ textField textRangeFromPosition : textField . beginningOfDocument toPosition : beforeExtensionPosition ] ;
[ textField performSelector : @ selector ( setSelectedTextRange : ) withObject : nameWithoutExtensionRange afterDelay : 0.1 ] ;
}
}
2016-06-03 21:33:26 +00:00
# pragma mark - Alert Delegate
2016-06-06 16:25:30 +00:00
- ( void ) alertView : ( UIAlertView * ) alertView willDismissWithButtonIndex : ( NSInteger ) buttonIndex {
2016-06-03 21:33:26 +00:00
if ( fileToRename && buttonIndex = = alertView . firstOtherButtonIndex ) {
[ self renameFile : fileToRename toName : nameTextField . text ] ;
fileToRename = nil ;
2016-06-06 16:25:30 +00:00
} else if ( createDiskImageAlert ! = nil ) {
NSString * name = [ self _newDiskImageName ] ;
off_t size = [ self _newDiskImageSize ] ;
createDiskImageAlert = nil ;
[ self createDiskImageWithName : name size : size ] ;
}
}
- ( BOOL ) alertViewShouldEnableFirstOtherButton : ( UIAlertView * ) alertView {
if ( alertView = = createDiskImageAlert ) {
return [ self validateCreateDiskImageInput : alertView ] ;
2016-06-03 21:33:26 +00:00
}
2016-06-06 16:25:30 +00:00
return YES ;
2016-06-03 21:33:26 +00:00
}
2016-05-11 21:04:49 +00:00
@ end
@ implementation FileTableViewCell
2016-07-02 21:06:09 +00:00
{
UIImage * defaultIcon ;
}
2016-05-11 21:04:49 +00:00
- ( void ) prepareForReuse {
[ super prepareForReuse ] ;
self . userInteractionEnabled = YES ;
self . textLabel . text = nil ;
self . textLabel . enabled = YES ;
self . imageView . image = nil ;
self . imageView . alpha = 1.0 ;
self . detailTextLabel . text = nil ;
2016-07-02 21:06:09 +00:00
if ( _filePath ) {
[ [ NSNotificationCenter defaultCenter ] removeObserver : self name : DidUpdateIconForDiskImageNotification object : _filePath ] ;
_filePath = nil ;
}
2016-05-11 21:04:49 +00:00
}
- ( void ) setFilePath : ( NSString * ) filePath {
2016-07-02 21:06:09 +00:00
NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter ] ;
if ( _filePath ) {
[ notificationCenter removeObserver : self name : DidUpdateIconForDiskImageNotification object : _filePath ] ;
}
2016-05-11 21:04:49 +00:00
_filePath = filePath ;
2016-07-02 21:06:09 +00:00
if ( _filePath ) {
[ notificationCenter addObserver : self selector : @ selector ( didUpdateDiskIcon : ) name : DidUpdateIconForDiskImageNotification object : _filePath ] ;
}
2016-05-11 21:04:49 +00:00
NSString * fileName = filePath . lastPathComponent ;
2016-06-04 13:13:08 +00:00
self . textLabel . text = self . showExtension ? fileName : fileName . stringByDeletingPathExtension ;
2016-06-06 17:29:53 +00:00
NSDictionary * attributes = [ [ NSURL fileURLWithPath : filePath ] resourceValuesForKeys : @ [ NSURLTotalFileSizeKey , NSURLFileSizeKey ] error : NULL ] ;
2016-05-11 21:04:49 +00:00
if ( attributes && attributes [ NSURLTotalFileSizeKey ] ) {
BOOL isDiskImage = [ [ AppDelegate sharedInstance ] . diskImageExtensions containsObject : fileName . pathExtension . lowercaseString ] ;
2016-05-21 13:01:57 +00:00
if ( isDiskImage ) {
2016-07-02 21:06:09 +00:00
NSInteger fileSize = [ attributes [ NSURLTotalFileSizeKey ] integerValue ] ;
NSInteger numBlocks = fileSize / 512 ;
defaultIcon = [ UIImage imageNamed : numBlocks = = 800 || numBlocks = = 1600 ? @ "floppy" : @ "floppyV" ] ;
self . imageView . image = [ UIImage imageWithIconForDiskImage : filePath ] ? : defaultIcon ;
2016-05-21 13:01:57 +00:00
} else {
2016-07-02 21:06:09 +00:00
defaultIcon = [ UIImage imageNamed : @ "document" ] ;
self . imageView . image = defaultIcon ;
2016-05-21 13:01:57 +00:00
}
2016-05-11 21:04:49 +00:00
NSString * sizeString = [ NSByteCountFormatter stringFromByteCount : [ attributes [ NSURLTotalFileSizeKey ] longLongValue ] countStyle : NSByteCountFormatterCountStyleBinary ] ;
self . detailTextLabel . text = sizeString ;
} else {
self . imageView . image = nil ;
self . detailTextLabel . text = nil ;
}
}
2016-07-02 21:06:09 +00:00
- ( void ) didUpdateDiskIcon : ( NSNotification * ) notification {
if ( [ _filePath isEqual : notification . object ] ) {
UIImage * icon = notification . userInfo [ @ "icon" ] ;
self . imageView . image = icon ? : defaultIcon ;
}
}
2016-05-11 21:04:49 +00:00
- ( void ) share : ( id ) sender {
UIActivityViewController * avc = [ [ UIActivityViewController alloc ] initWithActivityItems : @ [ [ NSURL fileURLWithPath : self . filePath ] ] applicationActivities : nil ] ;
2016-05-26 21:23:49 +00:00
if ( [ avc respondsToSelector : @ selector ( popoverPresentationController ) ] ) {
avc . modalPresentationStyle = UIModalPresentationPopover ;
avc . popoverPresentationController . sourceView = self . imageView ;
avc . popoverPresentationController . sourceRect = self . imageView . bounds ;
}
2016-05-11 21:04:49 +00:00
[ self . controller presentViewController : avc animated : YES completion : nil ] ;
}
- ( void ) rename : ( id ) sender {
[ self . controller askRenameFile : self . filePath ] ;
}
- ( void ) delete : ( id ) sender {
[ self . controller askDeleteFile : self . filePath ] ;
}
@ end