diff options
| author | Ronny Fenrich <Fenrich@Gmail.com> | 2013-06-14 11:42:17 -0600 |
|---|---|---|
| committer | Ronny Fenrich <Fenrich@Gmail.com> | 2013-06-14 11:42:17 -0600 |
| commit | c721c485f56cc2034f499a61c02117f31cc73da4 (patch) | |
| tree | 1989be521806bc34591f8ecc7ea2993c5f6afe93 | |
| parent | 0d40c8c8a1850559a9204b717585ba42ad4f2e9f (diff) | |
Finished Table view display of usage data
| -rw-r--r-- | Volta.xcodeproj/project.pbxproj | 28 | ||||
| -rw-r--r-- | Volta/Controls/VoltaButton.h | 13 | ||||
| -rw-r--r-- | Volta/Controls/VoltaButton.m | 23 | ||||
| -rw-r--r-- | Volta/Models/VoltaReading.h | 23 | ||||
| -rw-r--r-- | Volta/Models/VoltaReading.m | 55 | ||||
| -rw-r--r-- | Volta/Views/DataTableViewController.h | 13 | ||||
| -rw-r--r-- | Volta/Views/DataTableViewController.m | 105 | ||||
| -rw-r--r-- | Volta/Views/LoginViewController.m | 4 | ||||
| -rw-r--r-- | Volta/Views/StatsTabBarController.h | 17 | ||||
| -rw-r--r-- | Volta/Views/StatsTabBarController.m | 100 | ||||
| -rw-r--r-- | Volta/Views/StatsViewController.m | 126 | ||||
| -rw-r--r-- | Volta/Volta-Prefix.pch | 8 | ||||
| -rw-r--r-- | Volta/en.lproj/MainStoryboard.storyboard | 170 |
13 files changed, 635 insertions, 50 deletions
diff --git a/Volta.xcodeproj/project.pbxproj b/Volta.xcodeproj/project.pbxproj index 37c6dcf..718afe3 100644 --- a/Volta.xcodeproj/project.pbxproj +++ b/Volta.xcodeproj/project.pbxproj @@ -35,6 +35,10 @@ E31FF057176B551D009E4D27 /* grass@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E31FF056176B551D009E4D27 /* grass@2x.jpg */; }; E31FF059176B5639009E4D27 /* logo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E31FF058176B5639009E4D27 /* logo@2x.png */; }; E31FF05B176B58BC009E4D27 /* grass2@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E31FF05A176B58BC009E4D27 /* grass2@2x.jpg */; }; + E31FF05E176B5D79009E4D27 /* VoltaButton.m in Sources */ = {isa = PBXBuildFile; fileRef = E31FF05D176B5D79009E4D27 /* VoltaButton.m */; }; + E31FF061176B679E009E4D27 /* DataTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E31FF060176B679E009E4D27 /* DataTableViewController.m */; }; + E31FF064176B7D2D009E4D27 /* VoltaReading.m in Sources */ = {isa = PBXBuildFile; fileRef = E31FF063176B7D2D009E4D27 /* VoltaReading.m */; }; + E31FF067176B8B58009E4D27 /* StatsTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = E31FF066176B8B58009E4D27 /* StatsTabBarController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -84,6 +88,14 @@ E31FF056176B551D009E4D27 /* grass@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "grass@2x.jpg"; sourceTree = "<group>"; }; E31FF058176B5639009E4D27 /* logo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo@2x.png"; sourceTree = "<group>"; }; E31FF05A176B58BC009E4D27 /* grass2@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "grass2@2x.jpg"; sourceTree = "<group>"; }; + E31FF05C176B5D79009E4D27 /* VoltaButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoltaButton.h; sourceTree = "<group>"; }; + E31FF05D176B5D79009E4D27 /* VoltaButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VoltaButton.m; sourceTree = "<group>"; }; + E31FF05F176B679E009E4D27 /* DataTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataTableViewController.h; sourceTree = "<group>"; }; + E31FF060176B679E009E4D27 /* DataTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataTableViewController.m; sourceTree = "<group>"; }; + E31FF062176B7D2D009E4D27 /* VoltaReading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoltaReading.h; sourceTree = "<group>"; }; + E31FF063176B7D2D009E4D27 /* VoltaReading.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VoltaReading.m; sourceTree = "<group>"; }; + E31FF065176B8B58009E4D27 /* StatsTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatsTabBarController.h; sourceTree = "<group>"; }; + E31FF066176B8B58009E4D27 /* StatsTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatsTabBarController.m; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -198,6 +210,8 @@ E31FF036176A5677009E4D27 /* Controls */ = { isa = PBXGroup; children = ( + E31FF05C176B5D79009E4D27 /* VoltaButton.h */, + E31FF05D176B5D79009E4D27 /* VoltaButton.m */, ); path = Controls; sourceTree = "<group>"; @@ -232,6 +246,8 @@ E31FF03E176A5677009E4D27 /* Models */ = { isa = PBXGroup; children = ( + E31FF062176B7D2D009E4D27 /* VoltaReading.h */, + E31FF063176B7D2D009E4D27 /* VoltaReading.m */, ); path = Models; sourceTree = "<group>"; @@ -243,6 +259,10 @@ E31FF051176A5D9D009E4D27 /* LoginViewController.m */, E31FF053176A760D009E4D27 /* StatsViewController.h */, E31FF054176A760D009E4D27 /* StatsViewController.m */, + E31FF05F176B679E009E4D27 /* DataTableViewController.h */, + E31FF060176B679E009E4D27 /* DataTableViewController.m */, + E31FF065176B8B58009E4D27 /* StatsTabBarController.h */, + E31FF066176B8B58009E4D27 /* StatsTabBarController.m */, ); path = Views; sourceTree = "<group>"; @@ -383,6 +403,10 @@ E31FF04B176A5677009E4D27 /* SSKeychain.m in Sources */, E31FF052176A5D9D009E4D27 /* LoginViewController.m in Sources */, E31FF055176A760D009E4D27 /* StatsViewController.m in Sources */, + E31FF05E176B5D79009E4D27 /* VoltaButton.m in Sources */, + E31FF061176B679E009E4D27 /* DataTableViewController.m in Sources */, + E31FF064176B7D2D009E4D27 /* VoltaReading.m in Sources */, + E31FF067176B8B58009E4D27 /* StatsTabBarController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -481,11 +505,15 @@ isa = XCBuildConfiguration; baseConfigurationReference = 27E3918B8EF34D13A0A10AA7 /* Pods.xcconfig */; buildSettings = { + CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Volta/Volta-Prefix.pch"; INFOPLIST_FILE = "Volta/Volta-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.1; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/Volta/Controls/VoltaButton.h b/Volta/Controls/VoltaButton.h new file mode 100644 index 0000000..23d1c5c --- /dev/null +++ b/Volta/Controls/VoltaButton.h @@ -0,0 +1,13 @@ +// +// VoltaButton.h +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface VoltaButton : UIButton + +@end diff --git a/Volta/Controls/VoltaButton.m b/Volta/Controls/VoltaButton.m new file mode 100644 index 0000000..eab2fc0 --- /dev/null +++ b/Volta/Controls/VoltaButton.m @@ -0,0 +1,23 @@ +// +// VoltaButton.m +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import "VoltaButton.h" + +@implementation VoltaButton + +- (void)awakeFromNib +{ + [super awakeFromNib]; + + if (self.backgroundColor) + { + [self setBackgroundImage:[UIImage imageFromColor:[UIColor colorWithRed:0.214 green:0.573 blue:0.498 alpha:1.000]] forState:UIControlStateHighlighted]; + } +} + +@end diff --git a/Volta/Models/VoltaReading.h b/Volta/Models/VoltaReading.h new file mode 100644 index 0000000..325a4e4 --- /dev/null +++ b/Volta/Models/VoltaReading.h @@ -0,0 +1,23 @@ +// +// VoltaReading.h +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@interface VoltaReading : NSObject + ++ (VoltaReading *)initFromJSON:(NSDictionary *)jsonData; + +@property (nonatomic) NSInteger id; +@property (nonatomic) NSInteger usage; +@property (nonatomic) NSInteger duration; +@property (nonatomic) NSInteger cost; +@property (strong, nonatomic) NSDate *startDate; + +@property (strong, nonatomic) NSString *dictionaryKey; // Date of reading + +@end diff --git a/Volta/Models/VoltaReading.m b/Volta/Models/VoltaReading.m new file mode 100644 index 0000000..bd2d5fd --- /dev/null +++ b/Volta/Models/VoltaReading.m @@ -0,0 +1,55 @@ +// +// VoltaReading.m +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import "VoltaReading.h" + +@implementation VoltaReading + + ++ (VoltaReading *)initFromJSON:(NSDictionary *)jsonData; +{ + VoltaReading *result = [[VoltaReading alloc] init]; + + result.id = [[jsonData objectForKey:@"id"] integerValue]; + result.usage = [[jsonData objectForKey:@"usage"] integerValue]; + result.duration = [[jsonData objectForKey:@"duration"] integerValue]; + result.cost = [[jsonData objectForKey:@"cost"] integerValue]; + + // Dates + NSDateFormatter *inputDateParser = [[NSDateFormatter alloc] init]; + [inputDateParser setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; + NSString *startDateString = [jsonData objectForKey:@"start"] == [NSNull null] ? nil : [jsonData objectForKey:@"start"]; + if (!startDateString) + { + result.startDate = nil; + } + else + { + result.startDate = [inputDateParser dateFromString:startDateString]; + } + + return result; +} + + +- (NSString *)dictionaryKey +{ + if (self.startDate) + { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateStyle:NSDateFormatterFullStyle]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + return [dateFormatter stringFromDate:self.startDate]; + } + else + { + return @"unknown date"; + } +} + +@end diff --git a/Volta/Views/DataTableViewController.h b/Volta/Views/DataTableViewController.h new file mode 100644 index 0000000..f1b6e02 --- /dev/null +++ b/Volta/Views/DataTableViewController.h @@ -0,0 +1,13 @@ +// +// DataTableViewController.h +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface DataTableViewController : UITableViewController + +@end diff --git a/Volta/Views/DataTableViewController.m b/Volta/Views/DataTableViewController.m new file mode 100644 index 0000000..15667f3 --- /dev/null +++ b/Volta/Views/DataTableViewController.m @@ -0,0 +1,105 @@ +// +// DataTableViewController.m +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import "DataTableViewController.h" +#import "VoltaReading.h" +#import "MGOrderedDictionary.h" +#import "StatsTabBarController.h" + +@interface DataTableViewController () + +@property (strong, nonatomic) MGOrderedDictionary *data; // VoltaReading objects + + +@end + +@implementation DataTableViewController + + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updatedDataNotification) + name:NOTIFICATION_UPDATED_STATS_DATA + object:nil]; + +} + +- (void)updatedDataNotification +{ + [self.tableView reloadData]; +} + +- (MGOrderedDictionary *)data +{ + // get data from parent tabbar controller + StatsTabBarController *parentTabBarController = (StatsTabBarController *)self.parentViewController; + return parentTabBarController.data; +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + if (!self.data) + { + return 1; // Loading + } + else if (self.data.allKeys.count == 0) + { + return 1; // no data + } + else + { + return self.data.allKeys.count; + } +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (!self.data) + { + // still loading data + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LoadingCell"]; + return cell; + } + else if (self.data.count == 0) + { + // no results + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NoResultsCell"]; + return cell; + } + + // Configure the data cell... + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ReadingCell"]; + + NSString *dataKey = [self.data.allKeys objectAtIndex:indexPath.row]; + VoltaReading *reading = [self.data objectForKey:dataKey]; + + UILabel *dateLabel = (UILabel *)[cell viewWithTag:1]; + dateLabel.text = dataKey; + UILabel *kWhLabel = (UILabel *)[cell viewWithTag:2]; + float kWh = reading.usage / 1000.0f; + kWhLabel.text = [NSString stringWithFormat:@"%.2f kWh", kWh]; + UILabel *costLabel = (UILabel *)[cell viewWithTag:3]; + float cost = reading.cost / 100000.0f; + costLabel.text = [NSString stringWithFormat:@"%.2f $", cost]; + + return cell; +} + + + +@end diff --git a/Volta/Views/LoginViewController.m b/Volta/Views/LoginViewController.m index ba1c86b..34a12f6 100644 --- a/Volta/Views/LoginViewController.m +++ b/Volta/Views/LoginViewController.m @@ -122,10 +122,6 @@ #pragma mark - Action methods -- (IBAction)dismissKeyboard:(id)sender -{ - [self dismissKeyboard]; -} - (IBAction)backgroundTapped:(id)sender { diff --git a/Volta/Views/StatsTabBarController.h b/Volta/Views/StatsTabBarController.h new file mode 100644 index 0000000..7bfb622 --- /dev/null +++ b/Volta/Views/StatsTabBarController.h @@ -0,0 +1,17 @@ +// +// StatsTabBarController.h +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "MGOrderedDictionary.h" + + +@interface StatsTabBarController : UITabBarController + +@property (strong, nonatomic) MGOrderedDictionary *data; // VoltaReading objects + +@end diff --git a/Volta/Views/StatsTabBarController.m b/Volta/Views/StatsTabBarController.m new file mode 100644 index 0000000..cce66bb --- /dev/null +++ b/Volta/Views/StatsTabBarController.m @@ -0,0 +1,100 @@ +// +// StatsTabBarController.m +// Volta +// +// Created by Ronny Fenrich on 2013-06-14. +// Copyright (c) 2013 Decoder. All rights reserved. +// + +#import "StatsTabBarController.h" +#import "VoltaReading.h" + + +@interface StatsTabBarController () + +@end + +@implementation StatsTabBarController + + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // start loading data... + [self updateData]; +} + + +// -------------------------------------------------------------------------------------- +- (void)updateData +{ + self.data = nil; + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; + + // load data + AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:HOST]]; + [httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]]; + [httpClient setDefaultHeader:@"Accept" value:@"application/json"]; + [httpClient setParameterEncoding:AFJSONParameterEncoding]; + + // NSString *startDate = [self.queryDateFormatter stringFromDate:[NSDate date]]; + + NSError *error; + NSString *token = [SSKeychain passwordForService:KEYCHAIN_API_TOKEN account:KEYCHAIN_ACCOUNT error:&error]; + + NSMutableURLRequest *request; + request = [httpClient requestWithMethod:@"GET" path:[NSString stringWithFormat:URL_READINGS, token] parameters:nil]; + + NSLog(@"GET: %@", request); + + AFJSONRequestOperation *operation = [AFJSONRequestOperation + JSONRequestOperationWithRequest:request + success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) + { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + NSLog(@"%@", JSON); + + for (NSDictionary *data in JSON) + { + VoltaReading *aReading = [VoltaReading initFromJSON:data]; + NSString *dictKey = aReading.dictionaryKey; + if (!self.data) + { + self.data = [[MGOrderedDictionary alloc] init]; + } + + // we now group data by day (calc totals for days usage and cost) + if (![self.data objectForKey:dictKey]) + { + [self.data insertObject:aReading forKey:dictKey atIndex:self.data.count]; + } + else + { + VoltaReading *readingsForData = [self.data objectForKey:dictKey]; + aReading.cost += readingsForData.cost; + aReading.usage += readingsForData.usage; + [self.data setObject:aReading forKey:dictKey]; + } + } + + [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_UPDATED_STATS_DATA object:nil]; + } + failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) + { + NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo); + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_UPDATED_STATS_DATA object:nil]; + + BlockAlertView *alert = [BlockAlertView alertWithTitle:@"Error" message:@"Failed to retrieve reading data. Please try again later."]; + [alert setCancelButtonWithTitle:@"Ok" block:nil]; + [alert show]; + }]; + [operation start]; + + +} + + + +@end diff --git a/Volta/Views/StatsViewController.m b/Volta/Views/StatsViewController.m index 3862ad1..deb6a19 100644 --- a/Volta/Views/StatsViewController.m +++ b/Volta/Views/StatsViewController.m @@ -8,12 +8,14 @@ #import "StatsViewController.h" -@interface StatsViewController () +@interface StatsViewController ()<UITextFieldDelegate> @property (weak, nonatomic) IBOutlet UITextField *startDate; @property (weak, nonatomic) IBOutlet UITextField *endDate; @property (weak, nonatomic) IBOutlet UIScrollView *content; +@property (strong, nonatomic) UIDatePicker *startDatePicker; +@property (strong, nonatomic) UIDatePicker *endDatePicker; @end @implementation StatsViewController @@ -36,28 +38,130 @@ self.endDate.leftViewMode = UITextFieldViewModeAlways; self.content.$y = 0; -} -- (IBAction)statsCurrentMonth:(id)sender -{ + self.startDatePicker = [[UIDatePicker alloc] init]; + [self.startDatePicker setDatePickerMode:UIDatePickerModeDate]; + [self.startDatePicker addTarget:self action:@selector(startDatePickerValueChanged:) forControlEvents:UIControlEventValueChanged]; + self.startDate.inputView = self.startDatePicker; -} + self.endDatePicker = [[UIDatePicker alloc] init]; + [self.endDatePicker setDatePickerMode:UIDatePickerModeDate]; + [self.endDatePicker addTarget:self action:@selector(endDatePickerValueChanged:) forControlEvents:UIControlEventValueChanged]; + self.endDate.inputView = self.endDatePicker; -- (IBAction)statsLast30days:(id)sender { } -- (IBAction)statsLast60days:(id)sender { -} -- (IBAction)statsCurrentYear:(id)sender { +- (void)startDatePickerValueChanged:(id)sender +{ + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateStyle:NSDateFormatterShortStyle]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + self.startDate.text = [dateFormatter stringFromDate:[self.startDatePicker date]]; } -- (IBAction)statsStartdateEnddate:(id)sender { + +- (void)endDatePickerValueChanged:(id)sender +{ + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + self.endDate.text = [dateFormatter stringFromDate:[self.endDatePicker date]]; } -- (void)viewDidUnload { + + +- (void)viewDidUnload +{ [self setStartDate:nil]; [self setEndDate:nil]; [self setContent:nil]; [super viewDidUnload]; } + + +#pragma mark UITextFieldDelegate + + +#define SCROLLVIEW_HEIGHT 256 + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + // user did hit the Return/Done button on the keyboard + if (textField == self.startDate) + { + // goto password field + [self.endDate becomeFirstResponder]; + } + else + if (textField == self.endDate) + { + [self statsStartdateEnddate:nil]; + } + + return YES; +} + + +- (void)textFieldDidEndEditing:(UITextField *)textField +{ + [textField resignFirstResponder]; + + [self.content setContentOffset:CGPointZero animated:YES]; +// [self performBlock:^(id sender) { +// self.content.contentSize = CGSizeMake(self.content.frame.size.width, SCROLLVIEW_HEIGHT); +// } afterDelay:0.4]; +} + + +#define ACTIVE_TEXTFIELD_SCROLLVIEW_OFFSET 122 +- (void)textFieldDidBeginEditing:(UITextField *)textField +{ + self.content.contentSize = CGSizeMake(self.content.frame.size.width, SCROLLVIEW_HEIGHT + ACTIVE_TEXTFIELD_SCROLLVIEW_OFFSET); + [self.content setContentOffset:CGPointMake(0, ACTIVE_TEXTFIELD_SCROLLVIEW_OFFSET) animated:YES]; +} + + +- (void)dismissKeyboard +{ + [self.view endEditing:YES]; +} + + +#pragma mark - Action methods + + +- (IBAction)backgroundTapped:(id)sender +{ + [self dismissKeyboard]; +} + + +- (IBAction)statsCurrentMonth:(id)sender +{ + [self showStatsForStartDate:[NSDate date] endDate:[NSDate date]]; +} + +- (IBAction)statsLast30days:(id)sender +{ +} + +- (IBAction)statsLast60days:(id)sender +{ +} + +- (IBAction)statsCurrentYear:(id)sender +{ +} + +- (IBAction)statsStartdateEnddate:(id)sender +{ +} + + +- (void)showStatsForStartDate:(NSDate *)startDate endDate:(NSDate *)endDate +{ + [self performSegueWithIdentifier:@"ShowStatisticsSegue" sender:self]; +} + + @end diff --git a/Volta/Volta-Prefix.pch b/Volta/Volta-Prefix.pch index f196b32..0ec9e05 100644 --- a/Volta/Volta-Prefix.pch +++ b/Volta/Volta-Prefix.pch @@ -33,10 +33,12 @@ //#define HOST @"" // PROD #define HOST @"http://fast-gorge-5977.herokuapp.com" // DEV -#define URL_TOKEN @"?token=%@" #define URL_LOGIN @"/api/v1/logins" -#define URL_LOGOUT @"/logout" +//#define URL_LOGOUT @"/logout" + +#define URL_TOKEN @"?auth_token=%@" +#define URL_READINGS [@"/api/v1/readings" stringByAppendingString:URL_TOKEN] //#define URL_UPDATE_USER [@"/api/users/%d" stringByAppendingString:URL_TOKEN] @@ -57,7 +59,7 @@ // Notifications -#define NOTIFICATION_RELOAD_VIEW @"NOTIFICATION_RELOAD_VIEW" +#define NOTIFICATION_UPDATED_STATS_DATA @"NOTIFICATION_UPDATED_STATS_DATA" diff --git a/Volta/en.lproj/MainStoryboard.storyboard b/Volta/en.lproj/MainStoryboard.storyboard index cbe17dd..5c4c898 100644 --- a/Volta/en.lproj/MainStoryboard.storyboard +++ b/Volta/en.lproj/MainStoryboard.storyboard @@ -21,7 +21,7 @@ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Email address" minimumFontSize="17" clearButtonMode="whileEditing" id="4Wx-1t-eWb"> - <rect key="frame" x="155" y="130" width="170" height="30"/> + <rect key="frame" x="140" y="130" width="200" height="30"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="17"/> @@ -31,7 +31,7 @@ </connections> </textField> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" id="8gW-e7-dmr"> - <rect key="frame" x="155" y="167" width="170" height="30"/> + <rect key="frame" x="140" y="167" width="200" height="30"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="17"/> @@ -40,8 +40,8 @@ <outlet property="delegate" destination="2" id="Rn3-Vi-9zm"/> </connections> </textField> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="qNQ-ju-GIV"> - <rect key="frame" x="155" y="204" width="170" height="36"/> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="qNQ-ju-GIV" customClass="VoltaButton"> + <rect key="frame" x="140" y="204" width="200" height="36"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" red="0.26666666666666666" green="0.70588235294117652" blue="0.61176470588235299" alpha="1" colorSpace="calibratedRGB"/> <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="17"/> @@ -58,7 +58,7 @@ </button> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="logo@2x.png" id="kiQ-eY-yKl"> <rect key="frame" x="165" y="13" width="150" height="106"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> </imageView> </subviews> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> @@ -103,28 +103,100 @@ </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="WLB-YE-vcF" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="1602" y="1037"/> + <point key="canvasLocation" x="1567" y="855"/> </scene> - <!--View Controller - Table--> - <scene sceneID="Z8b-Q5-fhC"> + <!--Data Table View Controller - Your Usage--> + <scene sceneID="Kdy-I1-Sta"> <objects> - <viewController id="iov-Wj-U1x" sceneMemberID="viewController"> - <view key="view" contentMode="scaleToFill" id="frN-a3-8Kd"> + <tableViewController id="ByW-nL-NC8" customClass="DataTableViewController" sceneMemberID="viewController"> + <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Ryp-bT-wJh"> <rect key="frame" x="0.0" y="64" width="480" height="207"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/> - </view> - <tabBarItem key="tabBarItem" title="Table" id="tGC-Ag-uNg"/> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="EhK-Tt-ico" userLabel="First Responder" sceneMemberID="firstResponder"/> + <prototypes> + <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoadingCell" id="qUp-60-mmT"> + <rect key="frame" x="0.0" y="22" width="480" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> + <rect key="frame" x="0.0" y="0.0" width="480" height="43"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Loading..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mEJ-GU-Slx"> + <rect key="frame" x="20" y="11" width="440" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="17"/> + <color key="textColor" red="0.58431372550000005" green="0.58431372550000005" blue="0.58431372550000005" alpha="1" colorSpace="calibratedRGB"/> + <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </label> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + </view> + </tableViewCell> + <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="NoResultsCell" id="sb3-44-eSC"> + <rect key="frame" x="0.0" y="66" width="480" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> + <rect key="frame" x="0.0" y="0.0" width="480" height="43"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Sorry, no results for the selected time period." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zyT-03-PVt"> + <rect key="frame" x="20" y="11" width="440" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="17"/> + <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </label> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + </view> + </tableViewCell> + <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ReadingCell" id="y39-Mf-OGj"> + <rect key="frame" x="0.0" y="110" width="480" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> + <rect key="frame" x="0.0" y="0.0" width="480" height="43"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="1" contentMode="left" text="Date" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZWH-de-hMg"> + <rect key="frame" x="20" y="11" width="210" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="17"/> + <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </label> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="left" text="kWh" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="j5H-EF-l4l"> + <rect key="frame" x="274" y="11" width="94" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" red="0.059744625190929226" green="0.3174452774969066" blue="0.70396721363067627" alpha="1" colorSpace="calibratedRGB"/> + <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </label> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="3" contentMode="left" text="cost" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="KrD-A4-cWn"> + <rect key="frame" x="376" y="11" width="84" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" red="0.62515782828282829" green="0.40733053200850972" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </label> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + </view> + </tableViewCell> + </prototypes> + <connections> + <outlet property="dataSource" destination="ByW-nL-NC8" id="YcW-TT-HZh"/> + <outlet property="delegate" destination="ByW-nL-NC8" id="z91-9W-VSK"/> + </connections> + </tableView> + <tabBarItem key="tabBarItem" title="Your Usage" id="8lN-DZ-1vs"/> + </tableViewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="BhO-7f-fcd" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="1672" y="568"/> + <point key="canvasLocation" x="1709" y="431"/> </scene> - <!--Tab Bar Controller - Statistics--> + <!--Stats Tab Bar Controller - Statistics--> <scene sceneID="VvW-f8-jo2"> <objects> - <tabBarController definesPresentationContext="YES" id="f4D-Nl-1Q5" sceneMemberID="viewController"> + <tabBarController definesPresentationContext="YES" id="f4D-Nl-1Q5" customClass="StatsTabBarController" sceneMemberID="viewController"> <navigationItem key="navigationItem" title="Statistics" id="9AT-do-y0Z"/> <simulatedTabBarMetrics key="simulatedBottomBarMetrics"/> <tabBar key="tabBar" contentMode="scaleToFill" id="gDo-Eb-Z3G"> @@ -133,8 +205,9 @@ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> </tabBar> <connections> - <segue destination="iov-Wj-U1x" kind="relationship" relationship="viewControllers" id="ORp-hP-fbD"/> - <segue destination="jXX-Hl-vMK" kind="relationship" relationship="viewControllers" id="HV5-qo-jfa"/> + <segue destination="ByW-nL-NC8" kind="relationship" relationship="viewControllers" id="nPG-bp-40q"/> + <segue destination="jXX-Hl-vMK" kind="relationship" relationship="viewControllers" id="o57-g2-3P1"/> + <segue destination="17l-2f-bRP" kind="relationship" relationship="viewControllers" id="jgm-7K-0sS"/> </connections> </tabBarController> <placeholder placeholderIdentifier="IBFirstResponder" id="h6N-95-9pC" userLabel="First Responder" sceneMemberID="firstResponder"/> @@ -157,7 +230,7 @@ <rect key="frame" x="0.0" y="0.0" width="480" height="256"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Start Date" minimumFontSize="17" id="FTW-dx-T0r"> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Start Date" minimumFontSize="17" id="FTW-dx-T0r"> <rect key="frame" x="72" y="185" width="120" height="30"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> @@ -167,7 +240,7 @@ <outlet property="delegate" destination="lv2-8L-bY1" id="6TX-S1-CNs"/> </connections> </textField> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="cuU-tX-8gu"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="cuU-tX-8gu" customClass="VoltaButton"> <rect key="frame" x="368" y="183" width="92" height="34"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" red="0.2666666667" green="0.70588235290000001" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/> @@ -183,7 +256,7 @@ <action selector="statsStartdateEnddate:" destination="lv2-8L-bY1" eventType="touchUpInside" id="1Ce-Zq-1SS"/> </connections> </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="PJM-6d-TeN"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="PJM-6d-TeN" customClass="VoltaButton"> <rect key="frame" x="20" y="99" width="440" height="34"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" red="0.2666666667" green="0.70588235290000001" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/> @@ -199,7 +272,7 @@ <action selector="statsLast60days:" destination="lv2-8L-bY1" eventType="touchUpInside" id="jRX-gU-WT7"/> </connections> </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="X35-Uk-NCu"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="X35-Uk-NCu" customClass="VoltaButton"> <rect key="frame" x="20" y="141" width="440" height="34"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" red="0.2666666667" green="0.70588235290000001" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/> @@ -215,7 +288,7 @@ <action selector="statsCurrentYear:" destination="lv2-8L-bY1" eventType="touchUpInside" id="yoX-HF-OY9"/> </connections> </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="hCt-Nf-lhx"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="hCt-Nf-lhx" customClass="VoltaButton"> <rect key="frame" x="20" y="56" width="440" height="34"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" red="0.2666666667" green="0.70588235290000001" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/> @@ -231,7 +304,7 @@ <action selector="statsLast30days:" destination="lv2-8L-bY1" eventType="touchUpInside" id="A8M-3A-eP8"/> </connections> </button> - <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="End Date" minimumFontSize="17" id="7zh-ce-be2"> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="End Date" minimumFontSize="17" id="7zh-ce-be2"> <rect key="frame" x="232" y="185" width="120" height="30"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> @@ -241,7 +314,7 @@ <outlet property="delegate" destination="lv2-8L-bY1" id="aNe-SM-ZxM"/> </connections> </textField> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="Prl-07-V0C"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Prl-07-V0C" customClass="VoltaButton"> <rect key="frame" x="20" y="14" width="440" height="34"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <color key="backgroundColor" red="0.2666666667" green="0.70588235290000001" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/> @@ -272,6 +345,10 @@ <nil key="highlightedColor"/> </label> </subviews> + <gestureRecognizers/> + <connections> + <outletCollection property="gestureRecognizers" destination="gX5-Kf-fA1" appends="YES" id="zIe-u5-0Aj"/> + </connections> </scrollView> </subviews> <color key="backgroundColor" red="0.92549026010000002" green="0.91764712329999998" blue="0.90980398650000005" alpha="1" colorSpace="deviceRGB"/> @@ -283,10 +360,15 @@ <outlet property="content" destination="UXO-Vt-5K9" id="X3H-dT-rMp"/> <outlet property="endDate" destination="7zh-ce-be2" id="fH7-nO-NBJ"/> <outlet property="startDate" destination="FTW-dx-T0r" id="HE0-Xi-coM"/> - <segue destination="f4D-Nl-1Q5" kind="push" id="irZ-KB-Vgl"/> + <segue destination="f4D-Nl-1Q5" kind="push" identifier="ShowStatisticsSegue" id="irZ-KB-Vgl"/> </connections> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="90L-NY-XHf" userLabel="First Responder" sceneMemberID="firstResponder"/> + <tapGestureRecognizer id="gX5-Kf-fA1"> + <connections> + <action selector="backgroundTapped:" destination="lv2-8L-bY1" id="1lX-cd-DpL"/> + </connections> + </tapGestureRecognizer> </objects> <point key="canvasLocation" x="167" y="503"/> </scene> @@ -310,6 +392,22 @@ </objects> <point key="canvasLocation" x="-32" y="46"/> </scene> + <!--View Controller - Infographic--> + <scene sceneID="D4K-VQ-4G6"> + <objects> + <viewController id="17l-2f-bRP" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="bK0-Uh-lHN"> + <rect key="frame" x="0.0" y="64" width="480" height="207"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/> + </view> + <tabBarItem key="tabBarItem" title="Infographic" id="82e-hd-VoU"/> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="5KW-FB-f9B" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="1033" y="1047"/> + </scene> </scenes> <resources> <image name="grass2@2x.jpg" width="1100" height="846"/> @@ -317,26 +415,34 @@ <image name="logo@2x.png" width="234" height="166"/> </resources> <classes> + <class className="DataTableViewController" superclassName="UITableViewController"> + <source key="sourceIdentifier" type="project" relativePath="./Classes/DataTableViewController.h"/> + </class> <class className="LoginViewController" superclassName="UIViewController"> <source key="sourceIdentifier" type="project" relativePath="./Classes/LoginViewController.h"/> <relationships> - <relationship kind="action" name="backgroundTapped:"/> - <relationship kind="action" name="dismissKeyboard:"/> - <relationship kind="action" name="login:"/> <relationship kind="outlet" name="contentView" candidateClass="UIView"/> <relationship kind="outlet" name="email" candidateClass="UITextField"/> <relationship kind="outlet" name="logo" candidateClass="UIImageView"/> <relationship kind="outlet" name="password" candidateClass="UITextField"/> </relationships> </class> + <class className="StatsTabBarController" superclassName="UITabBarController"> + <source key="sourceIdentifier" type="project" relativePath="./Classes/StatsTabBarController.h"/> + </class> <class className="StatsViewController" superclassName="UIViewController"> <source key="sourceIdentifier" type="project" relativePath="./Classes/StatsViewController.h"/> <relationships> + <relationship kind="action" name="statsLast30days:"/> + <relationship kind="action" name="statsLast60days:"/> <relationship kind="outlet" name="content" candidateClass="UIScrollView"/> <relationship kind="outlet" name="endDate" candidateClass="UITextField"/> <relationship kind="outlet" name="startDate" candidateClass="UITextField"/> </relationships> </class> + <class className="VoltaButton" superclassName="UIButton"> + <source key="sourceIdentifier" type="project" relativePath="./Classes/VoltaButton.h"/> + </class> </classes> <simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedStatusBarMetrics key="statusBar"/> |
