Index: GridScheduler/GridScheduler/GSProgramGrid.h =================================================================== --- GridScheduler/GridScheduler/GSProgramGrid.h +++ GridScheduler/GridScheduler/GSProgramGrid.h @@ -30,13 +30,16 @@ /// The grid wants to be resized -(void)programGridWantsNewFrame:(CGRect)newFrame; +/// The program grid needs reloading +-(void)programGridNeedsReload; + @end /* * @class GSProgramGrid * @discussion UI control for the programs grid. */ -@interface GSProgramGrid : UIView +@interface GSProgramGrid : UIView /// Views to be laid out on the grid @property(nonatomic, readonly) NSMutableArray* programViews; Index: GridScheduler/GridScheduler/GSProgramGrid.m =================================================================== --- GridScheduler/GridScheduler/GSProgramGrid.m +++ GridScheduler/GridScheduler/GSProgramGrid.m @@ -11,6 +11,8 @@ #import "GSProgramGridPlaceholderOverlay.h" #import "NSString+GSString.h" #import "UIView+MLScreenshot.h" +#import "GSNetworking+ProgramSlot.h" +#import "GSProgramSlot.h" /// Seconds in a minute const double minutes = 60.0; @@ -104,6 +106,19 @@ } +/// shows an alert to the user indicating there is a conflict +- (void) showConflictMessage { + UIAlertView* alert = + [[UIAlertView alloc] initWithTitle:@"Conflicting changes" + message:@"It seems someone else made some changes over the same part of the grid, at the same time as you. We need to reload the grid to continue." + delegate:self cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + + [alert show]; +} + + + #pragma mark - Content layout /// Returns the Y coordinate for a given time @@ -235,14 +250,37 @@ programView.day = column; programView.start = [self timeForRow:row]; - [self layoutProgram:programView]; + + NSArray* deletedProgramIds = [self layoutProgram:programView]; - // TODO: save - -} - -/// Lays out a program on the correct spot --(void)layoutProgram:(GSProgramView*)programView { + // Saves the operation on the backend + GSProgramSlot* newProgramSlot = [GSProgramSlot new]; + newProgramSlot.programCode = programView.programIdentifier; + newProgramSlot.programSlotId = programView.slotIdentifier; + newProgramSlot.start = programView.start; + newProgramSlot.duration = programView.duration; + + [[GSNetworking sharedInstance] submitChanges:@[newProgramSlot] + andDeletes:deletedProgramIds + andNews:@[] + withCallback:^(BOOL success, BOOL conflict, NSArray *finalIds) { + + assert(success); + + if (conflict) { + [self showConflictMessage]; + } + + }]; + +} + +/* @discussion Lays out a program on the correct spot + * @return An array with the slot IDs of the removed and overlapped programs + */ +-(NSArray*)layoutProgram:(GSProgramView*)programView { + + NSMutableArray* ret = [NSMutableArray array]; // Move all overlapped views out of the grid for (GSProgramView* viewToRemove in self.programViews) { @@ -252,15 +290,16 @@ viewToRemove.start < programView.start + programView.duration) || (viewToRemove.start < programView.start && viewToRemove.start + viewToRemove.duration > programView.start)) { - [self.delegate programGridDidMoveProgramViewOutOfGrid:viewToRemove]; + [ret addObject:viewToRemove.slotIdentifier]; + [self.delegate programGridDidMoveProgramViewOutOfGrid:viewToRemove]; } } } - [self addSubview:programView]; programView.frame = [self rectForTime:programView.start duration:programView.duration andDay:programView.day]; + return ret; } -(void)programView:(GSProgramView *)programView expandTo:(CGPoint)vector { @@ -276,22 +315,44 @@ int copies = programView.frame.size.width / columnWidth; - // Expand to other days + // Program slot IDs to be deleted + NSMutableArray* deletes = [NSMutableArray array]; + + // Expand to this and other days for (int delta=0; delta < copies; delta++) { // Creates new program for copy days GSProgramView* program = programView; if (delta > 0) { - // TODO: copy program = [program copy]; [self addSubview:program]; } program.day += delta; - [self layoutProgram:program]; + [deletes addObjectsFromArray:[self layoutProgram:program]]; } + + // Saves the operation on the backend + GSProgramSlot* changedProgramSlot = [GSProgramSlot new]; + changedProgramSlot.programCode = programView.programIdentifier; + changedProgramSlot.programSlotId = programView.slotIdentifier; + changedProgramSlot.start = programView.start; + changedProgramSlot.duration = programView.duration; + + [[GSNetworking sharedInstance] submitChanges:@[changedProgramSlot] + andDeletes:deletes + andNews:@[] + withCallback:^(BOOL success, BOOL conflict, NSArray *finalIds) { + + assert(success); + + if (conflict) { + [self showConflictMessage]; + } + + }]; } @@ -351,6 +412,12 @@ } +#pragma mark - UIAlertViewDelegate methods + +-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + [self.delegate programGridNeedsReload]; +} + #pragma mark - Properties -(NSMutableArray *)programViews { Index: GridScheduler/GridScheduler/GSViewController.m =================================================================== --- GridScheduler/GridScheduler/GSViewController.m +++ GridScheduler/GridScheduler/GSViewController.m @@ -277,6 +277,10 @@ return pv; } +-(void)programGridNeedsReload { + [self loadWeek]; +} + -(void)programGridWantsNewFrame:(CGRect)newFrame { if (!CGRectEqualToRect(newFrame, CGRectNull)) {