diff --git a/DUREX Vendor Control/Base.lproj/Localizable.strings b/DUREX Vendor Control/Base.lproj/Localizable.strings index d77af42..fc52438 100644 --- a/DUREX Vendor Control/Base.lproj/Localizable.strings +++ b/DUREX Vendor Control/Base.lproj/Localizable.strings @@ -74,11 +74,16 @@ "50c Coins" = "50c Coins"; "Channel" = "Channel"; "Product Code" = "Product Code"; -"Normal Price" = "Normal Price"; +"Product Price" = "Product Price"; "Discounted Price" = "Discounted Price"; "1€ Change" = "1€ Change"; "50c Change" = "50c Change"; "Money Paid" = "Money Paid"; "Update Date & Time" = "Update Date & Time"; "Update product price" = "Update product price"; -"Update product name" = "Update product name"; \ No newline at end of file +"Update product name" = "Update product name"; +"Sale on" = "Sale on"; +"Report sent successfully" = "Report sent successfully"; +"Success!" = "Success!"; +"Connection to server failed" = "Connection to server failed"; +"Error" = "Error"; \ No newline at end of file diff --git a/DUREX Vendor Control/CommunicationProtocol.h b/DUREX Vendor Control/CommunicationProtocol.h index 772dd8a..ec8b4d5 100644 --- a/DUREX Vendor Control/CommunicationProtocol.h +++ b/DUREX Vendor Control/CommunicationProtocol.h @@ -13,11 +13,12 @@ #define MAX_RETRIES ((int)3) #define MAX_PRODUCT_NAME_LENGTH ((int)64) #define MAX_CHANNELS ((int)16) -#define MONEY_IN_NUM_UNITS ((int)5) -#define MONEY_OUT_NUM_UNITS ((int)3) -#define CHANGE_NUM_UNITS ((int)2) +#define MONEY_IN_NUM_UNITS ((int)6) +#define MONEY_OUT_NUM_UNITS ((int)3) +#define CHANGE_NUM_UNITS ((int)2) #define MAX_PRODUCTS ((int)16) #define SALE_STRING_LENGTH ((int)36) +#define REPORT_SERVER_URL @"http://seneca.upc.es:8090/machine" @interface CommunicationProtocol : NSObject diff --git a/DUREX Vendor Control/CommunicationProtocol.m b/DUREX Vendor Control/CommunicationProtocol.m index e80b91a..c1f414e 100644 --- a/DUREX Vendor Control/CommunicationProtocol.m +++ b/DUREX Vendor Control/CommunicationProtocol.m @@ -360,7 +360,7 @@ //NSString *answer = [self readMessage]; NSMutableString *answer = [[NSMutableString alloc]initWithString:@"P400255002550025510"]; - for(int i = 0; i < 15; i++) + for(int i = 0; i < 18; i++) { [answer appendString:@"0"]; } @@ -377,6 +377,7 @@ if([answer length] > 1 && [[answer substringToIndex:2]isEqualToString:@"P4"]) { + NSLog(@"[CommunicationProtocol.m]: sensorStatus returned: %@",answer); return answer; } return nil; @@ -415,10 +416,11 @@ [self writeMessage:command]; //NSString *answer = [self readMessage]; - NSMutableString *answer = [[NSMutableString alloc]initWithString:@"P21405141651102416090662045001500512P21406141651102416090662045001500512P2P2"]; - + /*NSMutableString *answer = [[NSMutableString alloc]initWithString:@"P21405141651010000000000620850050101P21407225404000002000100621050000001P2P2"];*/ + NSMutableString *answer = [[NSMutableString alloc]initWithString:@"P21408161036000001000000110450000001P21409012216000100000000220900000100P21409032307000000010502330800000000P21409070540000000020000440350000001P2P2"]; if([answer length] > 1 && [[answer substringToIndex:2]isEqualToString:@"P2"]) { + NSLog(@"[CommunicationProtocol.m]: saleLog returned: %@",answer); return answer; } return nil; diff --git a/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.pbxproj b/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.pbxproj index 658a587..0ac0485 100644 --- a/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.pbxproj +++ b/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ F989B60219BCE28C00657DD9 /* SalesLog.m in Sources */ = {isa = PBXBuildFile; fileRef = F989B60119BCE28C00657DD9 /* SalesLog.m */; }; F9A8EF7C192FE201009E7532 /* Stack.m in Sources */ = {isa = PBXBuildFile; fileRef = F9A8EF7B192FE201009E7532 /* Stack.m */; }; F9C77F50192CDE30002DBE8A /* system.json in Resources */ = {isa = PBXBuildFile; fileRef = F9C77F4F192CDE30002DBE8A /* system.json */; }; + F9CED59A19BE086E008F3764 /* UIView+Toast.m in Sources */ = {isa = PBXBuildFile; fileRef = F9CED59919BE086E008F3764 /* UIView+Toast.m */; }; F9E4D8FD19B8FD32009A7359 /* EMConnectingView_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = F9E4D8FF19B8FD32009A7359 /* EMConnectingView_iPad.xib */; }; /* End PBXBuildFile section */ @@ -131,6 +132,8 @@ F9A8EF7A192FE201009E7532 /* Stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stack.h; sourceTree = SOURCE_ROOT; }; F9A8EF7B192FE201009E7532 /* Stack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Stack.m; sourceTree = SOURCE_ROOT; }; F9C77F4F192CDE30002DBE8A /* system.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = system.json; sourceTree = SOURCE_ROOT; }; + F9CED59819BE086E008F3764 /* UIView+Toast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Toast.h"; sourceTree = SOURCE_ROOT; }; + F9CED59919BE086E008F3764 /* UIView+Toast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Toast.m"; sourceTree = SOURCE_ROOT; }; F9E4D8FE19B8FD32009A7359 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/EMConnectingView_iPad.xib; sourceTree = ""; }; F9E4D90119B8FD36009A7359 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/EMConnectingView_iPad.strings; sourceTree = ""; }; F9E4D90319B8FD37009A7359 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/EMConnectingView_iPad.strings; sourceTree = ""; }; @@ -184,6 +187,7 @@ 3471866618070D9300FA0FB2 /* DUREX Vendor Control */ = { isa = PBXGroup; children = ( + F9CED59719BE0863008F3764 /* Toast View */, 3471868F18070E4300FA0FB2 /* Framework */, 347186A718070F7F00FA0FB2 /* Device Picker */, 347186B91807290E00FA0FB2 /* Schemas */, @@ -268,6 +272,15 @@ name = Schemas; sourceTree = ""; }; + F9CED59719BE0863008F3764 /* Toast View */ = { + isa = PBXGroup; + children = ( + F9CED59819BE086E008F3764 /* UIView+Toast.h */, + F9CED59919BE086E008F3764 /* UIView+Toast.m */, + ); + name = "Toast View"; + sourceTree = ""; + }; F9ED745419B89E4600C7298D /* Views */ = { isa = PBXGroup; children = ( @@ -401,6 +414,7 @@ F933F80419B6819400521B90 /* DatePickerViewController.m in Sources */, F989B5FF19BCD7A100657DD9 /* Sale.m in Sources */, F98356D6192E835F00EA6821 /* InitialViewController.m in Sources */, + F9CED59A19BE086E008F3764 /* UIView+Toast.m in Sources */, F9A8EF7C192FE201009E7532 /* Stack.m in Sources */, 34AAB885189804FF0019860D /* EMDevicePickerViewController.m in Sources */, F989B60219BCE28C00657DD9 /* SalesLog.m in Sources */, diff --git a/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.xcworkspace/xcuserdata/imanol.xcuserdatad/UserInterfaceState.xcuserstate b/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.xcworkspace/xcuserdata/imanol.xcuserdatad/UserInterfaceState.xcuserstate index 0afb628..7b25ff8 100644 --- a/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.xcworkspace/xcuserdata/imanol.xcuserdatad/UserInterfaceState.xcuserstate +++ b/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/project.xcworkspace/xcuserdata/imanol.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/xcuserdata/imanol.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/xcuserdata/imanol.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index cf1192b..c5de594 100644 --- a/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/xcuserdata/imanol.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/DUREX Vendor Control/DUREX Vendor Control.xcodeproj/xcuserdata/imanol.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -26,11 +26,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "MenuTableViewController.m" - timestampString = "431828056.269485" + timestampString = "431887175.109814" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "599" - endingLineNumber = "599" + startingLineNumber = "724" + endingLineNumber = "724" landmarkName = "-tableView:cellForRowAtIndexPath:" landmarkType = "5"> @@ -42,11 +42,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "MenuTableViewController.m" - timestampString = "431828056.269485" + timestampString = "431887175.109814" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "541" - endingLineNumber = "541" + startingLineNumber = "666" + endingLineNumber = "666" landmarkName = "-tableView:cellForRowAtIndexPath:" landmarkType = "5"> @@ -58,11 +58,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "MenuTableViewController.m" - timestampString = "431828056.269485" + timestampString = "431887175.109814" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "423" - endingLineNumber = "423" + startingLineNumber = "522" + endingLineNumber = "522" landmarkName = "-tableView:didSelectRowAtIndexPath:" landmarkType = "5"> @@ -122,11 +122,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "MenuTableViewController.m" - timestampString = "431828056.269485" + timestampString = "431887175.109814" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "458" - endingLineNumber = "458" + startingLineNumber = "559" + endingLineNumber = "559" landmarkName = "-tableView:didSelectRowAtIndexPath:" landmarkType = "5"> @@ -138,11 +138,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "MenuTableViewController.m" - timestampString = "431828056.269485" + timestampString = "431887175.109814" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "457" - endingLineNumber = "457" + startingLineNumber = "558" + endingLineNumber = "558" landmarkName = "-tableView:didSelectRowAtIndexPath:" landmarkType = "5"> @@ -182,7 +182,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DUREX Vendor Control/FirstAppExample/Base.lproj/MainStoryboard.storyboard b/DUREX Vendor Control/FirstAppExample/Base.lproj/MainStoryboard.storyboard index 1bc2341..f22cf5b 100644 --- a/DUREX Vendor Control/FirstAppExample/Base.lproj/MainStoryboard.storyboard +++ b/DUREX Vendor Control/FirstAppExample/Base.lproj/MainStoryboard.storyboard @@ -1,5 +1,5 @@ - + @@ -119,25 +119,42 @@ - + - + + + + + + + + + + + + - diff --git a/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m b/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m index 4b0eec2..54b7333 100644 --- a/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m +++ b/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m @@ -105,7 +105,7 @@ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - [self performSegueWithIdentifier:@"ConnectionSegue" sender:self]; + //[self performSegueWithIdentifier:@"ConnectionSegue" sender:self]; if(![[[[tableView cellForRowAtIndexPath:indexPath] textLabel] text] isEqualToString:NSLocalizedString(@"Searching for devices...",nil)]) { [self _showConnectingView]; diff --git a/DUREX Vendor Control/MenuTableViewController.h b/DUREX Vendor Control/MenuTableViewController.h index 91fe92f..585b8f9 100644 --- a/DUREX Vendor Control/MenuTableViewController.h +++ b/DUREX Vendor Control/MenuTableViewController.h @@ -15,6 +15,7 @@ #import "NameChangerViewController.h" #import "Sensors.h" #import "SalesLog.h" +#import "UIView+Toast.h" #define num(x) [NSNumber numberWithUnsignedInt:x] @@ -26,16 +27,17 @@ #define MAINTENANCE_ELEMENTS @">[2000]Channels Present",@">[2001]Product Present in Channel",@">[2002]Channel Engine Status",@"[2003]Door Sensor",@"[2004]Coil Sensor",@">[2005]Money Collected",@">[2006]Money Returned",@">[2007]Products Sold",@">[2008]Change Available",@"[2009]Sales log",@"[2010]Incident report",@"[2011]Send report" #define MAINTENANCE_CHANNELS @"*Channel 1",@"*Channel 2",@"*Channel 3",@"*Channel 4",@"*Channel 5",@"*Channel 6",@"*Channel 7",@"*Channel 8",@"*Channel 9",@"*Channel 10",@"*Channel 11",@"*Channel 12",@"*Channel 13",@"*Channel 14",@"*Channel 15",@"*Channel 16" -#define MAINTENANCE_MONEY_IN @"*10€ Notes",@"*5€ Notes",@"*2€ Coins",@"*1€ Coins",@"*50c Coins" +#define MAINTENANCE_MONEY_IN @"*20€ Notes",@"*10€ Notes",@"*5€ Notes",@"*2€ Coins",@"*1€ Coins",@"*50c Coins" #define MAINTENANCE_MONEY_OUT @"*2€ Coins",@"*1€ Coins",@"*50c Coins" #define MAINTENANCE_CHANGE @"*1€ Coins",@"*50c Coins" #define MAINTENANCE_PRODUCTS @"*Product 1",@"*Product 2",@"*Product 3",@"*Product 4",@"*Product 5",@"*Product 6",@"*Product 7",@"*Product 8",@"*Product 9",@"*Product 10",@"*Product 11",@"*Product 12",@"*Product 13",@"*Product 14",@"*Product 15",@"*Product 16" #define MAINTENANCE_CELLS_PER_SECTION num(9),num(3) #define MAINTENANCE_HEADERS NSLocalizedString(@"Sensors", nil),NSLocalizedString(@"Commands", nil) -#define SALE_ELEMENTS @"[3000]Money Paid",@"[3001]Channel",@"[3002]Product Code",@"[3003]Normal Price",@"[3004]Discounted Price",@"[3005]Money Returned" -#define SALE_MONEY_PAID @"10€ Notes",@"5€ Notes",@"2€ Coins",@"1€ Coins",@"50c Coins" -#define SALE_MONEY_RETURNED @"1€ Change",@"50c Change" +#define SALE_ELEMENTS @">[3000]Money Paid",@"[3001]Channel",@"[3002]Product Code",@"[3003]Product Price",@">[3004]Money Returned" +#define SALE_MONEY_PAID @"*20€ Notes",@"*10€ Notes",@"*5€ Notes",@"*2€ Coins",@"*1€ Coins",@"*50c Coins" +#define SALE_MONEY_RETURNED @"*2€ Coins",@"*1€ Coins",@"*50c Coins" +#define SALE_CELLS_PER_SECTION num(5) #define SALE_HEADERS nil #define CONFIGURATION_ELEMENTS @"[4000]Update Date & Time",@"[4001]Update product price",@"[4002]Update product name" @@ -53,7 +55,7 @@ enum { REPORT, } navigationLevel; -@interface MenuTableViewController : UITableViewController +@interface MenuTableViewController : UITableViewController @property (strong,nonatomic) Stack *parentLayout; @property (strong,nonatomic) DatePickerViewController *datePickerViewController; @@ -61,6 +63,8 @@ enum { @property (strong,nonatomic) NameChangerViewController *nameChangerViewController; @property (strong,nonatomic) Sensors *sensorStatus; @property (strong,nonatomic) SalesLog *salesLog; +@property (strong,nonatomic) Sale *currentSale; +@property (strong,nonatomic) NSString *machineMACAddr; - (void) navBack; diff --git a/DUREX Vendor Control/MenuTableViewController.m b/DUREX Vendor Control/MenuTableViewController.m index 8fefc0f..f35a2f6 100644 --- a/DUREX Vendor Control/MenuTableViewController.m +++ b/DUREX Vendor Control/MenuTableViewController.m @@ -25,6 +25,10 @@ @property (nonatomic,strong) const NSMutableArray *saleListStructure; @property (nonatomic,strong) const NSMutableArray *saleListHeaders; +@property (nonatomic,strong) const NSMutableArray *saleElements; +@property (nonatomic,strong) const NSMutableArray *saleStructure; +@property (nonatomic,strong) const NSMutableArray *saleHeaders; + @property (nonatomic,strong) const NSMutableArray *configElements; @property (nonatomic,strong) const NSMutableArray *configStructure; @property (nonatomic,strong) const NSMutableArray *configHeaders; @@ -81,6 +85,9 @@ - (Boolean) generateMaintenanceLevel { + //Initialize sensor status + [self setSensorStatus:[[Sensors alloc]init]]; + NSString *sensorData = [_protocol readSensorData]; if(sensorData == nil) { @@ -103,6 +110,9 @@ - (Boolean) generateSaleListNavLevel { + //Initialize sales log + [self setSalesLog:[[SalesLog alloc]init]]; + //LAUNCH DATE RANGE SELECTOR NSString *salesData = [_protocol readSalesLog: nil : nil]; if(salesData == nil) @@ -111,12 +121,37 @@ return FALSE; } [[self salesLog] setResponseValue:salesData]; - [self setSaleListElements:[[NSMutableArray alloc] initWithObjects:nil, nil]]; - [self setSaleListStructure:[[NSMutableArray alloc] initWithObjects:nil, nil]]; + NSMutableArray *dateArray = [[NSMutableArray alloc] init]; + for(int i = 0; i < [[[self salesLog] sales]count]; i++) + { + Sale *currentSale = [[[self salesLog] sales]objectAtIndex:i]; + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSCalendarUnit units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit; + NSDateComponents *components = [calendar components:units fromDate:[currentSale saleTime]]; + [dateArray insertObject:[NSString stringWithFormat:@"[%d%d%d%d%d]%02d/%02d/%d %02d:%02d",[components day],[components month],[components year],[components hour],[components minute],[components day],[components month],[components year],[components hour],[components minute]] atIndex:i]; + } + [self setSaleListElements:[[NSMutableArray alloc] initWithArray:dateArray]]; + [self setSaleListStructure:[[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:[dateArray count]], nil]]; [self setSaleListHeaders:nil]; return TRUE; } +- (Boolean) generateSaleNavLevel : (NSInteger) numSale +{ + [self setSaleElements:[[NSMutableArray alloc] initWithObjects:SALE_ELEMENTS, nil]]; + [self setSaleStructure:[[NSMutableArray alloc] initWithObjects:SALE_CELLS_PER_SECTION, nil]]; + if([[self saleStructure] count] > 1) + { + [self setSaleHeaders:[[NSMutableArray alloc] initWithObjects:SALE_HEADERS, nil]]; + } + else + { + [self setSaleHeaders:nil]; + } + [self setCurrentSale:[[[self salesLog]sales]objectAtIndex:numSale]]; + return TRUE; +} + - (void) changeNavLevel: (uint8_t) level : (BOOL) push { NSLog(@"[MenuTableViewController.m]: navLevel is %d",level); @@ -128,7 +163,8 @@ [self setCurrentCellIdentifier:[[self cellIdentifiers] objectAtIndex:[self currentNavLevel]]]; if([self currentNavLevel] == MENU) { - [[self navigationItem] setTitle:[[[EMConnectionManager sharedManager] connectedDevice] name]]; + [self setMachineMACAddr:[[[EMConnectionManager sharedManager] connectedDevice] name]]; + [[self navigationItem] setTitle:[self machineMACAddr]]; [self setCurrentElements:[self menuElements]]; [self setCurrentStructure:[self menuStructure]]; [self setCurrentHeaders:[self menuHeaders]]; @@ -147,6 +183,16 @@ [self setCurrentStructure:[self saleListStructure]]; [self setCurrentHeaders:[self saleListHeaders]]; } + else if([self currentNavLevel] == SALE) + { + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSCalendarUnit units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit; + NSDateComponents *components = [calendar components:units fromDate:[[self currentSale] saleTime]]; + [[self navigationItem] setTitle:[NSString stringWithFormat:@"%@ %02d/%02d/%d %02d:%02d",NSLocalizedString(@"Sale on", nil),[components day],[components month],[components year],[components hour],[components minute]]]; + [self setCurrentElements:[self saleElements]]; + [self setCurrentStructure:[self saleStructure]]; + [self setCurrentHeaders:[self saleHeaders]]; + } else if([self currentNavLevel] == BASIC_CONFIGURATION) { [[self navigationItem] setTitle:NSLocalizedString(@"Basic Configuration", nil)]; @@ -155,6 +201,10 @@ [self setCurrentHeaders:[self configHeaders]]; } //AND SO ON... + NSLog(@"MenuTableViewController.m]: New elements: %@",[self currentElements]); + NSLog(@"MenuTableViewController.m]: New structure: %@",[self currentStructure]); + NSLog(@"MenuTableViewController.m]: New headers: %@",[self currentHeaders]); + NSLog(@"MenuTableViewController.m]: New cell identifier: %@",[self currentCellIdentifier]); [self reloadTable:UITableViewRowAnimationAutomatic]; } @@ -198,6 +248,32 @@ } } +- (void) sendMaintenanceReport : (NSString*) status : (NSString*) date : (NSString*) machineid +{ + NSString *content = [NSString stringWithFormat:@"status=%@&date=%@&machineid=%@",status,date,machineid]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:REPORT_SERVER_URL]]; + [request setHTTPMethod:@"POST"]; + [request setHTTPBody:[content dataUsingEncoding:NSUTF8StringEncoding]]; + + // generates an autoreleased NSURLConnection + [NSURLConnection connectionWithRequest:request delegate:self]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + // Append the new data to receivedData. + // receivedData is an instance variable declared elsewhere. + NSLog(@"[MenuTableViewController.m]: Received response from report server: %@",[NSString stringWithUTF8String:[data bytes]]); + [self.view makeToast:NSLocalizedString(@"Report sent successfully", nil) duration:3 position:[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2)] title:NSLocalizedString(@"Success!", nil) image:[UIImage imageNamed:@"icon_checkmark"]]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + NSLog(@"[MenuTableViewController.m]: Error connecting to server: %@ %@",[error localizedDescription],[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]); + [self.view makeToast:NSLocalizedString(@"Connection to server failed", nil) duration:3 position:[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2)] title:NSLocalizedString(@"Error", nil) image:[UIImage imageNamed:@"icon_delete"]]; +} + - (void)viewDidLoad { [super viewDidLoad]; @@ -227,13 +303,7 @@ [self initializeMenuEntries]; self.currentNavLevel = 255; [self changeNavLevel:MENU:FALSE]; - - //Initialize sensor status - [self setSensorStatus:[[Sensors alloc]init]]; - - //Initialize sales log - [self setSalesLog:[[SalesLog alloc]init]]; -} + } -(void)viewDidAppear:(BOOL)animated { @@ -386,6 +456,35 @@ } } } + else if([self currentNavLevel] == SALE) + { + if([cellName isEqualToString:@"Money Paid"]) + { + NSMutableArray *newRows = [[NSMutableArray alloc] initWithObjects:SALE_MONEY_PAID, nil]; + if(folded) + { + [self addTags: newRows : cellTag]; + [self addRowsAtIndexPath: newRows : index]; + } + else + { + [self removeRowsAtIndexPath: [newRows count] : index]; + } + } + else if([cellName isEqualToString:@"Money Returned"]) + { + NSMutableArray *newRows = [[NSMutableArray alloc] initWithObjects:SALE_MONEY_RETURNED, nil]; + if(folded) + { + [self addTags: newRows : cellTag]; + [self addRowsAtIndexPath: newRows : index]; + } + else + { + [self removeRowsAtIndexPath: [newRows count] : index]; + } + } + } [self reloadTable:UITableViewRowAnimationNone]; } @@ -422,6 +521,7 @@ NSLog(@"[MenuTableViewController.m]: Changing to navLevel: MAINTENANCE"); if([self generateMaintenanceLevel]) { + [NSThread sleepForTimeInterval:1]; [self changeNavLevel:MAINTENANCE:TRUE]; } else @@ -454,6 +554,7 @@ } else if([cellName isEqualToString:NSLocalizedString(@"Sales log", nil)]) { + [NSThread sleepForTimeInterval:1]; NSLog(@"[MenuTableViewController.m]: Changing to navLevel: SALE_LIST"); if([self generateSaleListNavLevel]) { @@ -464,6 +565,14 @@ NSLog(@"[MenuTableViewController.m]: Error while changing to navLevel: SALE_LIST"); } } + else if([cellName isEqualToString:NSLocalizedString(@"Send report", nil)]) + { + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSCalendarUnit units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; + NSDateComponents *components = [calendar components:units fromDate:[NSDate date]]; + NSString *date = [NSString stringWithFormat:@"%02d/%02d/%d %02d:%02d:%02d",[components day],[components month],[components year],[components hour],[components minute],[components second]]; + [self sendMaintenanceReport: [[self sensorStatus] response] : date: [self machineMACAddr]]; + } } //Cells in BASIC_CONFIGURATION else if([self currentNavLevel] == BASIC_CONFIGURATION) @@ -517,6 +626,22 @@ } } } + else if([self currentNavLevel] == SALE_LIST) + { + if([self generateSaleNavLevel: [indexPath row]]) + { + [self changeNavLevel:SALE:TRUE]; + } + } + else if([self currentNavLevel] == SALE) + { + if([cellName isEqualToString:NSLocalizedString(@"Money Paid", nil)] || + [cellName isEqualToString:NSLocalizedString(@"Money Returned", nil)]) + { + [self toggleDropList:indexPath]; + } + + } } #pragma mark - Table view data source @@ -701,11 +826,12 @@ else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Money Collected",nil)]) { double numCollected = 0; - numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:0] intValue] * 10; - numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:1] intValue] * 5; - numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:2] intValue] * 2; - numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:3] intValue] * 1; - numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:4] intValue] * 0.50; + numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:0] intValue] * 20; + numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:1] intValue] * 10; + numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:2] intValue] * 5; + numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:3] intValue] * 2; + numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:4] intValue] * 1; + numCollected += [[[[self sensorStatus] moneyCollected] objectAtIndex:5] intValue] * 0.50; [[cell detailTextLabel] setText:[NSString stringWithFormat:@"%.2f",numCollected]]; } else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Money Returned",nil)]) @@ -746,26 +872,33 @@ } } } - else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"10€ Notes",nil)]) + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"20€ Notes",nil)]) { if([cell tag] == 2005) { [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:0] stringValue]]; } } - else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"5€ Notes",nil)]) + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"10€ Notes",nil)]) { if([cell tag] == 2005) { [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:1] stringValue]]; } } - else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"2€ Coins",nil)]) + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"5€ Notes",nil)]) { if([cell tag] == 2005) { [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:2] stringValue]]; } + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"2€ Coins",nil)]) + { + if([cell tag] == 2005) + { + [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:3] stringValue]]; + } else if([cell tag] == 2006) { [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyReturned] objectAtIndex:0] stringValue]]; @@ -775,7 +908,7 @@ { if([cell tag] == 2005) { - [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:3] stringValue]]; + [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:4] stringValue]]; } else if([cell tag] == 2006) { @@ -797,7 +930,7 @@ { if([cell tag] == 2005) { - [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:4] stringValue]]; + [[cell detailTextLabel] setText:[[[[self sensorStatus] moneyCollected] objectAtIndex:5] stringValue]]; } else if([cell tag] == 2006) { @@ -824,6 +957,119 @@ [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; } } + else if([self currentNavLevel] == SALE) + { + [[[cell contentView] viewWithTag:CELL_CARAT_TAG] removeFromSuperview]; + [[cell detailTextLabel] setText:@""]; + [cell setAccessoryView:nil]; + [cell setAccessoryType:UITableViewCellAccessoryNone]; + if(foldedList) + { + NSInteger cellHeight = cell.contentView.frame.size.height; + UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,cellHeight/2 - (11/2),11,11)]; + imageView.image = [UIImage imageNamed:@"carat.png"]; + imageView.tag = CELL_CARAT_TAG; + [cell.contentView addSubview:imageView]; + } + else if(unfoldedList) + { + NSInteger cellHeight = cell.contentView.frame.size.height; + UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,cellHeight/2 - (11/2),11,11)]; + imageView.image = [UIImage imageNamed:@"carat-open.png"]; + imageView.tag = CELL_CARAT_TAG; + [cell.contentView addSubview:imageView]; + } + if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Money Paid",nil)]) + { + double numCollected = 0; + numCollected += [[[[self currentSale] moneyPaid] objectAtIndex:0] intValue] * 20; + numCollected += [[[[self currentSale] moneyPaid] objectAtIndex:1] intValue] * 10; + numCollected += [[[[self currentSale] moneyPaid] objectAtIndex:2] intValue] * 5; + numCollected += [[[[self currentSale] moneyPaid] objectAtIndex:3] intValue] * 2; + numCollected += [[[[self currentSale] moneyPaid] objectAtIndex:4] intValue] * 1; + numCollected += [[[[self currentSale] moneyPaid] objectAtIndex:5] intValue] * 0.50; + [[cell detailTextLabel] setText:[NSString stringWithFormat:@"%.2f",numCollected]]; + [cell setAccessoryView:nil]; + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Channel",nil)]) + { + [[cell detailTextLabel] setText:[[self currentSale] channel]]; + [cell setAccessoryView:nil]; + } + if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Product Code",nil)]) + { + [[cell detailTextLabel] setText:[[self currentSale] productCode]]; + [cell setAccessoryView:nil]; + } + if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Product Price",nil)]) + { + [[cell detailTextLabel] setText:[[self currentSale] normalPrice]]; + [cell setAccessoryView:nil]; + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"Money Returned",nil)]) + { + double numReturned = 0; + numReturned += [[[[self currentSale] moneyReturned] objectAtIndex:0] intValue] * 2; + numReturned += [[[[self currentSale] moneyReturned] objectAtIndex:1] intValue] * 1; + numReturned += [[[[self currentSale] moneyReturned] objectAtIndex:2] intValue] * 0.50; + [[cell detailTextLabel] setText:[NSString stringWithFormat:@"%.2f",numReturned]]; + [cell setAccessoryView:nil]; + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"20€ Notes",nil)]) + { + if([cell tag] == 3000) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyPaid] objectAtIndex:0] stringValue]]; + } + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"10€ Notes",nil)]) + { + if([cell tag] == 3000) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyPaid] objectAtIndex:1] stringValue]]; + } + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"5€ Notes",nil)]) + { + if([cell tag] == 3000) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyPaid] objectAtIndex:2] stringValue]]; + } + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"2€ Coins",nil)]) + { + if([cell tag] == 3000) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyPaid] objectAtIndex:3] stringValue]]; + } + else if([cell tag] == 3004) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyReturned] objectAtIndex:0] stringValue]]; + } + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"1€ Coins",nil)]) + { + if([cell tag] == 3000) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyPaid] objectAtIndex:4] stringValue]]; + } + else if([cell tag] == 3004) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyReturned] objectAtIndex:1] stringValue]]; + } + } + else if([[[cell textLabel] text] isEqualToString:NSLocalizedString(@"50c Coins",nil)]) + { + if([cell tag] == 3000) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyPaid]objectAtIndex:5] stringValue]]; + } + else if([cell tag] == 3004) + { + [[cell detailTextLabel] setText:[[[[self currentSale] moneyReturned] objectAtIndex:2] stringValue]]; + } + } + } return cell; } diff --git a/DUREX Vendor Control/Sale.h b/DUREX Vendor Control/Sale.h index dacc79c..0d901be 100644 --- a/DUREX Vendor Control/Sale.h +++ b/DUREX Vendor Control/Sale.h @@ -15,7 +15,6 @@ @property (strong,nonatomic) NSMutableArray *moneyReturned; @property NSString *productCode; @property NSString *normalPrice; -@property NSString *discountedPrice; @property NSString *channel; @property NSDate *saleTime; diff --git a/DUREX Vendor Control/SalesLog.m b/DUREX Vendor Control/SalesLog.m index f054923..363dbbe 100644 --- a/DUREX Vendor Control/SalesLog.m +++ b/DUREX Vendor Control/SalesLog.m @@ -38,24 +38,24 @@ [saleDate setDay:[[[self response] substringWithRange:NSMakeRange(6 + currentSale*SALE_STRING_LENGTH, 2)] intValue]]; [saleDate setHour:[[[self response] substringWithRange:NSMakeRange(8 + currentSale*SALE_STRING_LENGTH, 2)] intValue]]; [saleDate setMinute:[[[self response] substringWithRange:NSMakeRange(10 + currentSale*SALE_STRING_LENGTH, 2)] intValue]]; - [sale setSaleTime:[saleDate date]]; - NSLog(@"date: %@",saleDate); + [sale setSaleTime:[calendar dateFromComponents:saleDate]]; + NSLog(@"date: %@",[calendar dateFromComponents:saleDate]); [[sale moneyPaid] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(12 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:0]; [[sale moneyPaid] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(14 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:1]; [[sale moneyPaid] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(16 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:2]; [[sale moneyPaid] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(18 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:3]; [[sale moneyPaid] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(20 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:4]; + [[sale moneyPaid] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(22 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:5]; NSLog(@"moneyPaid: %@",[sale moneyPaid]); - [sale setChannel:[[self response] substringWithRange:NSMakeRange(22 + currentSale*SALE_STRING_LENGTH, 1)]]; + [sale setChannel:[[self response] substringWithRange:NSMakeRange(24 + currentSale*SALE_STRING_LENGTH, 1)]]; NSLog(@"channel: %@",[sale channel]); - [sale setProductCode:[[self response] substringWithRange:NSMakeRange(23 + currentSale*SALE_STRING_LENGTH, 1)]]; + [sale setProductCode:[[self response] substringWithRange:NSMakeRange(25 + currentSale*SALE_STRING_LENGTH, 1)]]; NSLog(@"productCode: %@",[sale productCode]); - [sale setNormalPrice: [NSString stringWithFormat:@"%d,%02d",[[[self response] substringWithRange:NSMakeRange(24 + currentSale*SALE_STRING_LENGTH, 2)] intValue],[[[self response] substringWithRange:NSMakeRange(26 + currentSale*SALE_STRING_LENGTH, 2)] intValue]]]; + [sale setNormalPrice: [NSString stringWithFormat:@"%d,%02d €",[[[self response] substringWithRange:NSMakeRange(26 + currentSale*SALE_STRING_LENGTH, 2)] intValue],[[[self response] substringWithRange:NSMakeRange(28 + currentSale*SALE_STRING_LENGTH, 2)] intValue]]]; NSLog(@"normalPrice: %@",[sale normalPrice]); - [sale setDiscountedPrice: [NSString stringWithFormat:@"%d,%02d",[[[self response] substringWithRange:NSMakeRange(28 + currentSale*SALE_STRING_LENGTH, 2)] intValue],[[[self response] substringWithRange:NSMakeRange(30 + currentSale*SALE_STRING_LENGTH, 2)] intValue]]]; - NSLog(@"discountedPrice: %@",[sale discountedPrice]); - [[sale moneyReturned] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(32 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:0]; - [[sale moneyReturned] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(34 + currentSale*SALE_STRING_LENGTH , 2)] intValue]] atIndex:1]; + [[sale moneyReturned] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(30 + currentSale*SALE_STRING_LENGTH, 2)] intValue]] atIndex:0]; + [[sale moneyReturned] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(32 + currentSale*SALE_STRING_LENGTH , 2)] intValue]] atIndex:1]; + [[sale moneyReturned] insertObject:[NSNumber numberWithInt:[[[self response] substringWithRange:NSMakeRange(34 + currentSale*SALE_STRING_LENGTH , 2)] intValue]] atIndex:2]; NSLog(@"moneyReturned: %@",[sale moneyReturned]); [[self sales] insertObject:sale atIndex:currentSale]; currentSale++; diff --git a/DUREX Vendor Control/Sensors.m b/DUREX Vendor Control/Sensors.m index 15d2667..e46e77f 100644 --- a/DUREX Vendor Control/Sensors.m +++ b/DUREX Vendor Control/Sensors.m @@ -126,7 +126,7 @@ substrRange.location += 2; } - if([[self response] characterAtIndex:75] == '1') + if([[self response] characterAtIndex:78] == '1') { [[self changeAvailable]insertObject:[NSNumber numberWithBool:TRUE] atIndex:0]; } @@ -135,7 +135,7 @@ [[self changeAvailable]insertObject:[NSNumber numberWithBool:FALSE] atIndex:0]; } - if([[self response] characterAtIndex:76] == '1') + if([[self response] characterAtIndex:79] == '1') { [[self changeAvailable]insertObject:[NSNumber numberWithBool:TRUE] atIndex:1]; } diff --git a/DUREX Vendor Control/UIView+Toast.h b/DUREX Vendor Control/UIView+Toast.h new file mode 100755 index 0000000..f4c1832 --- /dev/null +++ b/DUREX Vendor Control/UIView+Toast.h @@ -0,0 +1,50 @@ +/*************************************************************************** + +UIView+Toast.h +Toast + +Copyright (c) 2013 Charles Scalesse. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +***************************************************************************/ + + +#import + +@interface UIView (Toast) + +// each makeToast method creates a view and displays it as toast +- (void)makeToast:(NSString *)message; +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position; +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position image:(UIImage *)image; +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position title:(NSString *)title; +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position title:(NSString *)title image:(UIImage *)image; + +// displays toast with an activity spinner +- (void)makeToastActivity; +- (void)makeToastActivity:(id)position; +- (void)hideToastActivity; + +// the showToast methods display any view as toast +- (void)showToast:(UIView *)toast; +- (void)showToast:(UIView *)toast duration:(NSTimeInterval)interval position:(id)point; + +@end diff --git a/DUREX Vendor Control/UIView+Toast.m b/DUREX Vendor Control/UIView+Toast.m new file mode 100755 index 0000000..00408d5 --- /dev/null +++ b/DUREX Vendor Control/UIView+Toast.m @@ -0,0 +1,365 @@ +// +// UIView+Toast.m +// Toast +// +// Copyright 2013 Charles Scalesse. +// + +#import "UIView+Toast.h" +#import +#import + +/* + * CONFIGURE THESE VALUES TO ADJUST LOOK & FEEL, + * DISPLAY DURATION, ETC. + */ + +// general appearance +static const CGFloat CSToastMaxWidth = 0.8; // 80% of parent view width +static const CGFloat CSToastMaxHeight = 0.8; // 80% of parent view height +static const CGFloat CSToastHorizontalPadding = 10.0; +static const CGFloat CSToastVerticalPadding = 10.0; +static const CGFloat CSToastCornerRadius = 10.0; +static const CGFloat CSToastOpacity = 0.8; +static const CGFloat CSToastFontSize = 16.0; +static const CGFloat CSToastMaxTitleLines = 0; +static const CGFloat CSToastMaxMessageLines = 0; +static const NSTimeInterval CSToastFadeDuration = 0.2; + +// shadow appearance +static const CGFloat CSToastShadowOpacity = 0.8; +static const CGFloat CSToastShadowRadius = 6.0; +static const CGSize CSToastShadowOffset = { 4.0, 4.0 }; +static const BOOL CSToastDisplayShadow = YES; + +// display duration and position +static const NSString * CSToastDefaultPosition = @"bottom"; +static const NSTimeInterval CSToastDefaultDuration = 3.0; + +// image view size +static const CGFloat CSToastImageViewWidth = 80.0; +static const CGFloat CSToastImageViewHeight = 80.0; + +// activity +static const CGFloat CSToastActivityWidth = 100.0; +static const CGFloat CSToastActivityHeight = 100.0; +static const NSString * CSToastActivityDefaultPosition = @"center"; + +// interaction +static const BOOL CSToastHidesOnTap = YES; // excludes activity views + +// associative reference keys +static const NSString * CSToastTimerKey = @"CSToastTimerKey"; +static const NSString * CSToastActivityViewKey = @"CSToastActivityViewKey"; + +@interface UIView (ToastPrivate) + +- (void)hideToast:(UIView *)toast; +- (void)toastTimerDidFinish:(NSTimer *)timer; +- (void)handleToastTapped:(UITapGestureRecognizer *)recognizer; +- (CGPoint)centerPointForPosition:(id)position withToast:(UIView *)toast; +- (UIView *)viewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image; +- (CGSize)sizeForString:(NSString *)string font:(UIFont *)font constrainedToSize:(CGSize)constrainedSize lineBreakMode:(NSLineBreakMode)lineBreakMode; + +@end + + +@implementation UIView (Toast) + +#pragma mark - Toast Methods + +- (void)makeToast:(NSString *)message { + [self makeToast:message duration:CSToastDefaultDuration position:CSToastDefaultPosition]; +} + +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position { + UIView *toast = [self viewForMessage:message title:nil image:nil]; + [self showToast:toast duration:duration position:position]; +} + +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title { + UIView *toast = [self viewForMessage:message title:title image:nil]; + [self showToast:toast duration:duration position:position]; +} + +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position image:(UIImage *)image { + UIView *toast = [self viewForMessage:message title:nil image:image]; + [self showToast:toast duration:duration position:position]; +} + +- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title image:(UIImage *)image { + UIView *toast = [self viewForMessage:message title:title image:image]; + [self showToast:toast duration:duration position:position]; +} + +- (void)showToast:(UIView *)toast { + [self showToast:toast duration:CSToastDefaultDuration position:CSToastDefaultPosition]; +} + +- (void)showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)point { + toast.center = [self centerPointForPosition:point withToast:toast]; + toast.alpha = 0.0; + + if (CSToastHidesOnTap) { + UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:toast action:@selector(handleToastTapped:)]; + [toast addGestureRecognizer:recognizer]; + toast.userInteractionEnabled = YES; + toast.exclusiveTouch = YES; + } + + [self addSubview:toast]; + + [UIView animateWithDuration:CSToastFadeDuration + delay:0.0 + options:(UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction) + animations:^{ + toast.alpha = 1.0; + } completion:^(BOOL finished) { + NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(toastTimerDidFinish:) userInfo:toast repeats:NO]; + // associate the timer with the toast view + objc_setAssociatedObject (toast, &CSToastTimerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + }]; + +} + +- (void)hideToast:(UIView *)toast { + [UIView animateWithDuration:CSToastFadeDuration + delay:0.0 + options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState) + animations:^{ + toast.alpha = 0.0; + } completion:^(BOOL finished) { + [toast removeFromSuperview]; + }]; +} + +#pragma mark - Events + +- (void)toastTimerDidFinish:(NSTimer *)timer { + [self hideToast:(UIView *)timer.userInfo]; +} + +- (void)handleToastTapped:(UITapGestureRecognizer *)recognizer { + NSTimer *timer = (NSTimer *)objc_getAssociatedObject(self, &CSToastTimerKey); + [timer invalidate]; + + [self hideToast:recognizer.view]; +} + +#pragma mark - Toast Activity Methods + +- (void)makeToastActivity { + [self makeToastActivity:CSToastActivityDefaultPosition]; +} + +- (void)makeToastActivity:(id)position { + // sanity + UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey); + if (existingActivityView != nil) return; + + UIView *activityView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CSToastActivityWidth, CSToastActivityHeight)]; + activityView.center = [self centerPointForPosition:position withToast:activityView]; + activityView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:CSToastOpacity]; + activityView.alpha = 0.0; + activityView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); + activityView.layer.cornerRadius = CSToastCornerRadius; + + if (CSToastDisplayShadow) { + activityView.layer.shadowColor = [UIColor blackColor].CGColor; + activityView.layer.shadowOpacity = CSToastShadowOpacity; + activityView.layer.shadowRadius = CSToastShadowRadius; + activityView.layer.shadowOffset = CSToastShadowOffset; + } + + UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + activityIndicatorView.center = CGPointMake(activityView.bounds.size.width / 2, activityView.bounds.size.height / 2); + [activityView addSubview:activityIndicatorView]; + [activityIndicatorView startAnimating]; + + // associate the activity view with self + objc_setAssociatedObject (self, &CSToastActivityViewKey, activityView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + [self addSubview:activityView]; + + [UIView animateWithDuration:CSToastFadeDuration + delay:0.0 + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + activityView.alpha = 1.0; + } completion:nil]; +} + +- (void)hideToastActivity { + UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey); + if (existingActivityView != nil) { + [UIView animateWithDuration:CSToastFadeDuration + delay:0.0 + options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState) + animations:^{ + existingActivityView.alpha = 0.0; + } completion:^(BOOL finished) { + [existingActivityView removeFromSuperview]; + objc_setAssociatedObject (self, &CSToastActivityViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + }]; + } +} + +#pragma mark - Helpers + +- (CGPoint)centerPointForPosition:(id)point withToast:(UIView *)toast { + if([point isKindOfClass:[NSString class]]) { + // convert string literals @"top", @"bottom", @"center", or any point wrapped in an NSValue object into a CGPoint + if([point caseInsensitiveCompare:@"top"] == NSOrderedSame) { + return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + CSToastVerticalPadding); + } else if([point caseInsensitiveCompare:@"bottom"] == NSOrderedSame) { + return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - CSToastVerticalPadding); + } else if([point caseInsensitiveCompare:@"center"] == NSOrderedSame) { + return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); + } + } else if ([point isKindOfClass:[NSValue class]]) { + return [point CGPointValue]; + } + + NSLog(@"Warning: Invalid position for toast."); + return [self centerPointForPosition:CSToastDefaultPosition withToast:toast]; +} + +- (CGSize)sizeForString:(NSString *)string font:(UIFont *)font constrainedToSize:(CGSize)constrainedSize lineBreakMode:(NSLineBreakMode)lineBreakMode { + if ([string respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.lineBreakMode = lineBreakMode; + NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}; + CGRect boundingRect = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; + return CGSizeMake(ceilf(boundingRect.size.width), ceilf(boundingRect.size.height)); + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [string sizeWithFont:font constrainedToSize:constrainedSize lineBreakMode:lineBreakMode]; +#pragma clang diagnostic pop +} + +- (UIView *)viewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image { + // sanity + if((message == nil) && (title == nil) && (image == nil)) return nil; + + // dynamically build a toast view with any combination of message, title, & image. + UILabel *messageLabel = nil; + UILabel *titleLabel = nil; + UIImageView *imageView = nil; + + // create the parent view + UIView *wrapperView = [[UIView alloc] init]; + wrapperView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); + wrapperView.layer.cornerRadius = CSToastCornerRadius; + + if (CSToastDisplayShadow) { + wrapperView.layer.shadowColor = [UIColor blackColor].CGColor; + wrapperView.layer.shadowOpacity = CSToastShadowOpacity; + wrapperView.layer.shadowRadius = CSToastShadowRadius; + wrapperView.layer.shadowOffset = CSToastShadowOffset; + } + + wrapperView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:CSToastOpacity]; + + if(image != nil) { + imageView = [[UIImageView alloc] initWithImage:image]; + imageView.contentMode = UIViewContentModeScaleAspectFit; + imageView.frame = CGRectMake(CSToastHorizontalPadding, CSToastVerticalPadding, CSToastImageViewWidth, CSToastImageViewHeight); + } + + CGFloat imageWidth, imageHeight, imageLeft; + + // the imageView frame values will be used to size & position the other views + if(imageView != nil) { + imageWidth = imageView.bounds.size.width; + imageHeight = imageView.bounds.size.height; + imageLeft = CSToastHorizontalPadding; + } else { + imageWidth = imageHeight = imageLeft = 0.0; + } + + if (title != nil) { + titleLabel = [[UILabel alloc] init]; + titleLabel.numberOfLines = CSToastMaxTitleLines; + titleLabel.font = [UIFont boldSystemFontOfSize:CSToastFontSize]; + titleLabel.textAlignment = NSTextAlignmentLeft; + titleLabel.lineBreakMode = NSLineBreakByWordWrapping; + titleLabel.textColor = [UIColor whiteColor]; + titleLabel.backgroundColor = [UIColor clearColor]; + titleLabel.alpha = 1.0; + titleLabel.text = title; + + // size the title label according to the length of the text + CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * CSToastMaxWidth) - imageWidth, self.bounds.size.height * CSToastMaxHeight); + CGSize expectedSizeTitle = [self sizeForString:title font:titleLabel.font constrainedToSize:maxSizeTitle lineBreakMode:titleLabel.lineBreakMode]; + titleLabel.frame = CGRectMake(0.0, 0.0, expectedSizeTitle.width, expectedSizeTitle.height); + } + + if (message != nil) { + messageLabel = [[UILabel alloc] init]; + messageLabel.numberOfLines = CSToastMaxMessageLines; + messageLabel.font = [UIFont systemFontOfSize:CSToastFontSize]; + messageLabel.lineBreakMode = NSLineBreakByWordWrapping; + messageLabel.textColor = [UIColor whiteColor]; + messageLabel.backgroundColor = [UIColor clearColor]; + messageLabel.alpha = 1.0; + messageLabel.text = message; + + // size the message label according to the length of the text + CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * CSToastMaxWidth) - imageWidth, self.bounds.size.height * CSToastMaxHeight); + CGSize expectedSizeMessage = [self sizeForString:message font:messageLabel.font constrainedToSize:maxSizeMessage lineBreakMode:messageLabel.lineBreakMode]; + messageLabel.frame = CGRectMake(0.0, 0.0, expectedSizeMessage.width, expectedSizeMessage.height); + } + + // titleLabel frame values + CGFloat titleWidth, titleHeight, titleTop, titleLeft; + + if(titleLabel != nil) { + titleWidth = titleLabel.bounds.size.width; + titleHeight = titleLabel.bounds.size.height; + titleTop = CSToastVerticalPadding; + titleLeft = imageLeft + imageWidth + CSToastHorizontalPadding; + } else { + titleWidth = titleHeight = titleTop = titleLeft = 0.0; + } + + // messageLabel frame values + CGFloat messageWidth, messageHeight, messageLeft, messageTop; + + if(messageLabel != nil) { + messageWidth = messageLabel.bounds.size.width; + messageHeight = messageLabel.bounds.size.height; + messageLeft = imageLeft + imageWidth + CSToastHorizontalPadding; + messageTop = titleTop + titleHeight + CSToastVerticalPadding; + } else { + messageWidth = messageHeight = messageLeft = messageTop = 0.0; + } + + CGFloat longerWidth = MAX(titleWidth, messageWidth); + CGFloat longerLeft = MAX(titleLeft, messageLeft); + + // wrapper width uses the longerWidth or the image width, whatever is larger. same logic applies to the wrapper height + CGFloat wrapperWidth = MAX((imageWidth + (CSToastHorizontalPadding * 2)), (longerLeft + longerWidth + CSToastHorizontalPadding)); + CGFloat wrapperHeight = MAX((messageTop + messageHeight + CSToastVerticalPadding), (imageHeight + (CSToastVerticalPadding * 2))); + + wrapperView.frame = CGRectMake(0.0, 0.0, wrapperWidth, wrapperHeight); + + if(titleLabel != nil) { + titleLabel.frame = CGRectMake(titleLeft, titleTop, titleWidth, titleHeight); + [wrapperView addSubview:titleLabel]; + } + + if(messageLabel != nil) { + messageLabel.frame = CGRectMake(messageLeft, messageTop, messageWidth, messageHeight); + [wrapperView addSubview:messageLabel]; + } + + if(imageView != nil) { + [wrapperView addSubview:imageView]; + } + + return wrapperView; +} + +@end diff --git a/DUREX Vendor Control/en.lproj/Localizable.strings b/DUREX Vendor Control/en.lproj/Localizable.strings index 0fbeb31..934b0e5 100644 --- a/DUREX Vendor Control/en.lproj/Localizable.strings +++ b/DUREX Vendor Control/en.lproj/Localizable.strings @@ -74,11 +74,16 @@ "50c Coins" = "50c Coins"; "Channel" = "Channel"; "Product Code" = "Product Code"; -"Normal Price" = "Normal Price"; +"Product Price" = "Product Price"; "Discounted Price" = "Discounted Price"; "Money Paid" = "Money Paid"; "1€ Change" = "1€ Change"; "50c Change" = "50c Change"; "Update Date & Time" = "Update Date & Time"; "Update product price" = "Update product price"; -"Update product name" = "Update product name"; \ No newline at end of file +"Update product name" = "Update product name"; +"Sale on" = "Sale on"; +"Report sent successfully" = "Report sent successfully"; +"Success!" = "Success!"; +"Connection to server failed" = "Connection to server failed"; +"Error" = "Error"; \ No newline at end of file diff --git a/DUREX Vendor Control/es.lproj/Localizable.strings b/DUREX Vendor Control/es.lproj/Localizable.strings index 1024332..233d233 100644 --- a/DUREX Vendor Control/es.lproj/Localizable.strings +++ b/DUREX Vendor Control/es.lproj/Localizable.strings @@ -74,11 +74,16 @@ "50c Coins" = "Monedas de 50c"; "Channel" = "Canal"; "Product Code" = "Código del producto"; -"Normal Price" = "Precio Normal"; +"Product Price" = "Precio del Producto"; "Discounted Price" = "Precio con descuento"; "Money Paid" = "Efectivo Pagado"; "1€ Change" = "Cambio de 1€"; "50c Change" = "Cambio de 50c"; "Update Date & Time" = "Actualizar fecha y hora"; "Update product price" = "Actualizar precio del producto"; -"Update product name" = "Actualizar nombre del producto"; \ No newline at end of file +"Update product name" = "Actualizar nombre del producto"; +"Sale on" = "Venta el"; +"Report sent successfully" = "Informe enviado satisfactoriamente"; +"Success!" = "Éxito!"; +"Connection to server failed" = "Conexión al servidor fallida"; +"Error" = "Error"; \ No newline at end of file diff --git a/TODO b/TODO index 77b1d47..b120af9 100644 --- a/TODO +++ b/TODO @@ -7,13 +7,6 @@ BUGS: TODO: -- Populate sale list with dates -- On select any date, generate navlevel with index in salesLog -- Generate sale navLevel - -- Implement sensor status logging and sending to remote server -- Lewis infrastructure for data viewing (SQL, Webpage, CSV parser) - - Channels and codes to 2 ciphers - Incident class @@ -24,4 +17,4 @@ TODO: - Implement master key. CHECK: -- Layouts on another iPhone +- Layouts on another iPhone (4 inch)