From 00775b4235087b882fa0eccea56e97863cc04a07 Mon Sep 17 00:00:00 2001 From: lizj0505 Date: Thu, 18 Jul 2013 19:59:24 +0800 Subject: [PATCH] create issue functionality done, not with parameter exception checked yet --- .../RedmineMobile.xcodeproj/project.pbxproj | 12 +- .../RedmineMobile/Models/OZLModelIssue.h | 5 +- .../RedmineMobile/Models/OZLModelIssue.m | 15 +- ...odelPriority.h => OZLModelIssuePriority.h} | 4 +- ...odelPriority.m => OZLModelIssuePriority.m} | 6 +- .../RedmineMobile/Models/OZLModelUser.h | 7 + .../RedmineMobile/Models/OZLModelUser.m | 9 +- .../RedmineMobile/Utils/OZLNetwork.h | 11 +- .../RedmineMobile/Utils/OZLNetwork.m | 140 ++++++- .../OZLIssueCreateViewController.h | 20 +- .../OZLIssueCreateViewController.m | 354 +++++++++++++++++- .../OZLIssueCreateViewController.storyboard | 205 +++++----- .../OZLIssueDetailViewController.m | 4 +- .../OZLProjectCreateViewController.m | 2 +- .../OZLProjectViewController.m | 3 +- 15 files changed, 674 insertions(+), 123 deletions(-) rename RedmineMobile/RedmineMobile/Models/{OZLModelPriority.h => OZLModelIssuePriority.h} (79%) rename RedmineMobile/RedmineMobile/Models/{OZLModelPriority.m => OZLModelIssuePriority.m} (77%) diff --git a/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj b/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj index 35f7bba..5c991c2 100644 --- a/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj +++ b/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj @@ -36,7 +36,7 @@ 2BCF881E1793F3C8006FC859 /* OZLModelIssue.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF881D1793F3C8006FC859 /* OZLModelIssue.m */; }; 2BCF88211793F478006FC859 /* OZLModelTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF88201793F478006FC859 /* OZLModelTracker.m */; }; 2BCF88271793F4AA006FC859 /* OZLModelIssueStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF88261793F4AA006FC859 /* OZLModelIssueStatus.m */; }; - 2BCF882A1793F4C9006FC859 /* OZLModelPriority.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF88291793F4C9006FC859 /* OZLModelPriority.m */; }; + 2BCF882A1793F4C9006FC859 /* OZLModelIssuePriority.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF88291793F4C9006FC859 /* OZLModelIssuePriority.m */; }; 2BCF88301793F5CE006FC859 /* OZLModelUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF882F1793F5CE006FC859 /* OZLModelUser.m */; }; D5DB805A1792F2BF0081662A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB80591792F2BF0081662A /* UIKit.framework */; }; D5DB805C1792F2BF0081662A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB805B1792F2BF0081662A /* Foundation.framework */; }; @@ -115,8 +115,8 @@ 2BCF88201793F478006FC859 /* OZLModelTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelTracker.m; path = Models/OZLModelTracker.m; sourceTree = ""; }; 2BCF88251793F4AA006FC859 /* OZLModelIssueStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelIssueStatus.h; path = Models/OZLModelIssueStatus.h; sourceTree = ""; }; 2BCF88261793F4AA006FC859 /* OZLModelIssueStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelIssueStatus.m; path = Models/OZLModelIssueStatus.m; sourceTree = ""; }; - 2BCF88281793F4C9006FC859 /* OZLModelPriority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelPriority.h; path = Models/OZLModelPriority.h; sourceTree = ""; }; - 2BCF88291793F4C9006FC859 /* OZLModelPriority.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelPriority.m; path = Models/OZLModelPriority.m; sourceTree = ""; }; + 2BCF88281793F4C9006FC859 /* OZLModelIssuePriority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelIssuePriority.h; path = Models/OZLModelIssuePriority.h; sourceTree = ""; }; + 2BCF88291793F4C9006FC859 /* OZLModelIssuePriority.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelIssuePriority.m; path = Models/OZLModelIssuePriority.m; sourceTree = ""; }; 2BCF882E1793F5CE006FC859 /* OZLModelUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelUser.h; path = Models/OZLModelUser.h; sourceTree = ""; }; 2BCF882F1793F5CE006FC859 /* OZLModelUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelUser.m; path = Models/OZLModelUser.m; sourceTree = ""; }; D5DB80561792F2BF0081662A /* RedmineMobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RedmineMobile.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -446,8 +446,8 @@ 2BCF881D1793F3C8006FC859 /* OZLModelIssue.m */, 2BCF881F1793F478006FC859 /* OZLModelTracker.h */, 2BCF88201793F478006FC859 /* OZLModelTracker.m */, - 2BCF88281793F4C9006FC859 /* OZLModelPriority.h */, - 2BCF88291793F4C9006FC859 /* OZLModelPriority.m */, + 2BCF88281793F4C9006FC859 /* OZLModelIssuePriority.h */, + 2BCF88291793F4C9006FC859 /* OZLModelIssuePriority.m */, 2BCF882E1793F5CE006FC859 /* OZLModelUser.h */, 2BCF882F1793F5CE006FC859 /* OZLModelUser.m */, 2B9968A91794F71B0086F115 /* OZLModelIssueCategory.h */, @@ -566,7 +566,7 @@ 2BCF881E1793F3C8006FC859 /* OZLModelIssue.m in Sources */, 2BCF88211793F478006FC859 /* OZLModelTracker.m in Sources */, 2BCF88271793F4AA006FC859 /* OZLModelIssueStatus.m in Sources */, - 2BCF882A1793F4C9006FC859 /* OZLModelPriority.m in Sources */, + 2BCF882A1793F4C9006FC859 /* OZLModelIssuePriority.m in Sources */, 2BCF88301793F5CE006FC859 /* OZLModelUser.m in Sources */, 2B9968AB1794F71B0086F115 /* OZLModelIssueCategory.m in Sources */, 2B9968AF1794FC0A0086F115 /* OZLProjectCreateViewController.m in Sources */, diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssue.h b/RedmineMobile/RedmineMobile/Models/OZLModelIssue.h index 129c120..e646a79 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelIssue.h +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssue.h @@ -10,7 +10,7 @@ #import "OZLModelTracker.h" #import "OZLModelIssueStatus.h" #import "OZLModelUser.h" -#import "OZLModelPriority.h" +#import "OZLModelIssuePriority.h" #import "OZLModelIssueCategory.h" @interface OZLModelIssue : NSObject @@ -21,7 +21,7 @@ @property(nonatomic,strong) OZLModelTracker* tracker; @property(nonatomic,strong) OZLModelUser* author; @property(nonatomic,strong) OZLModelUser* assignedTo; -@property(nonatomic,strong) OZLModelPriority* priority; +@property(nonatomic,strong) OZLModelIssuePriority* priority; @property(nonatomic,strong) OZLModelIssueStatus* status; @property(nonatomic,strong) OZLModelIssueCategory* category; @property(nonatomic,strong) NSString* subject; @@ -32,6 +32,7 @@ @property(nonatomic,strong) NSString* updatedOn; @property(nonatomic) float doneRatio; @property(nonatomic) float spentHours; +@property(nonatomic) float estimatedHours; @property(nonatomic,strong) NSString* notes;// used as paramter to update a issue -(id)initWithDictionary:(NSDictionary*)dic; diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssue.m b/RedmineMobile/RedmineMobile/Models/OZLModelIssue.m index 4eba26d..55064cd 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelIssue.m +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssue.m @@ -38,7 +38,7 @@ } id priority = [dic objectForKey:@"priority"]; if (priority != nil) { - _priority = [[OZLModelPriority alloc] initWithDictionary:priority]; + _priority = [[OZLModelIssuePriority alloc] initWithDictionary:priority]; } id status = [dic objectForKey:@"status"]; if (status) { @@ -61,6 +61,13 @@ }else { _spentHours = 0.0f; } + id estimatedHours = [dic objectForKey:@"estimated_hours"]; + if (spentHours ) { + _estimatedHours = [estimatedHours floatValue]; + }else { + _estimatedHours = 0.0f; + } + return self; } -(NSMutableDictionary*) toParametersDic @@ -93,6 +100,12 @@ if (_parentIssueId > 0) { [issueData setObject:[NSNumber numberWithInt:_parentIssueId] forKey:@"parent_issue_id"]; } + if (_spentHours > 0) { + [issueData setObject:[NSNumber numberWithFloat:_spentHours] forKey:@"spent_hours"]; + } + if (_estimatedHours > 0) { + [issueData setObject:[NSNumber numberWithFloat:_estimatedHours] forKey:@"estimated_hours"]; + } return [[NSMutableDictionary alloc] initWithObjectsAndKeys:issueData,@"issue",nil]; } diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelPriority.h b/RedmineMobile/RedmineMobile/Models/OZLModelIssuePriority.h similarity index 79% rename from RedmineMobile/RedmineMobile/Models/OZLModelPriority.h rename to RedmineMobile/RedmineMobile/Models/OZLModelIssuePriority.h index 2cb49ae..7894d6d 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelPriority.h +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssuePriority.h @@ -1,5 +1,5 @@ // -// OZLModelPriority.h +// OZLModelIssuePriority.h // RedmineMobile // // Created by lizhijie on 7/15/13. @@ -8,7 +8,7 @@ #import -@interface OZLModelPriority : NSObject +@interface OZLModelIssuePriority : NSObject @property(nonatomic) int index; @property(nonatomic, strong) NSString* name; diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelPriority.m b/RedmineMobile/RedmineMobile/Models/OZLModelIssuePriority.m similarity index 77% rename from RedmineMobile/RedmineMobile/Models/OZLModelPriority.m rename to RedmineMobile/RedmineMobile/Models/OZLModelIssuePriority.m index 1be7ceb..70c34ba 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelPriority.m +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssuePriority.m @@ -1,14 +1,14 @@ // -// OZLModelPriority.m +// OZLModelIssuePriority.m // RedmineMobile // // Created by lizhijie on 7/15/13. // Copyright (c) 2013 Lee Zhijie. All rights reserved. // -#import "OZLModelPriority.h" +#import "OZLModelIssuePriority.h" -@implementation OZLModelPriority +@implementation OZLModelIssuePriority -(id)initWithDictionary:(NSDictionary*)dic { diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelUser.h b/RedmineMobile/RedmineMobile/Models/OZLModelUser.h index a2ea548..1658380 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelUser.h +++ b/RedmineMobile/RedmineMobile/Models/OZLModelUser.h @@ -11,6 +11,13 @@ @interface OZLModelUser : NSObject @property(nonatomic) int index; +@property(nonatomic, strong) NSString* login; +@property(nonatomic, strong) NSString* firstname; +@property(nonatomic, strong) NSString* lastname; +@property(nonatomic, strong) NSString* mail; +@property(nonatomic, strong) NSString* createdOn; +@property(nonatomic, strong) NSString* lastLoginIn; + @property(nonatomic, strong) NSString* name; -(id)initWithDictionary:(NSDictionary*)dic; diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelUser.m b/RedmineMobile/RedmineMobile/Models/OZLModelUser.m index ea313b6..2537f1c 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelUser.m +++ b/RedmineMobile/RedmineMobile/Models/OZLModelUser.m @@ -18,9 +18,16 @@ } _index = [[dic objectForKey:@"id"] intValue]; - _name = [dic objectForKey:@"name"]; + _login = [dic objectForKey:@"login"]; + _firstname = [dic objectForKey:@"firstname"]; + _lastname = [dic objectForKey:@"lastname"]; + _mail = [dic objectForKey:@"mail"]; + _createdOn = [dic objectForKey:@"created_on"]; + _lastLoginIn = [dic objectForKey:@"last_login_on"]; + _name = _login; return self; } + @end diff --git a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h index eff58ca..35ab89c 100644 --- a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h +++ b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h @@ -29,7 +29,7 @@ #import #import "OZLModelProject.h" #import "OZLModelIssue.h" -#import "OZLModelPriority.h" +#import "OZLModelIssuePriority.h" #import "OZLModelIssueStatus.h" #import "OZLModelTracker.h" #import "OZLModelUser.h" @@ -51,5 +51,14 @@ +(void)updateIssue:(OZLModelIssue*)issueData withParams:(NSDictionary*)params andBlock:(void (^)(BOOL success, NSError *error))block; +(void)deleteIssue:(int)issueid withParams:(NSDictionary*)params andBlock:(void (^)(BOOL success, NSError *error))block; +// priority ++(void)getPriorityListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; +// user ++(void)getUserListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; +// issue status ++(void)getIssueStatusListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; +// tracker ++(void)getTrackerListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; + @end diff --git a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m index 96e41d8..7bec7e8 100644 --- a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m +++ b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m @@ -267,8 +267,7 @@ if (block) { NSLog(@"the repsonse:%@",responseObject); - int repondNumber = [responseObject intValue]; - block(repondNumber == 201,nil); + block(YES,nil); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { @@ -336,4 +335,141 @@ }]; } + +#pragma mark - +#pragma mark priority api +// priority ++(void)getPriorityListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block +{ + NSString* path = @"/enumerations/issue_priorities.json"; + NSMutableDictionary* paramsDic = [[NSMutableDictionary alloc] initWithDictionary:params]; + NSString* accessKey = [[OZLSingleton sharedInstance] redmineUserKey]; + if (accessKey.length > 0) { + [paramsDic setObject:accessKey forKey:@"key"]; + } + + [[OZLNetworkBase sharedClient] setAuthorizationHeader]; + [[OZLNetworkBase sharedClient] getPath:path parameters:paramsDic success:^(AFHTTPRequestOperation *operation, id responseObject) { + + if (block) { + NSLog(@"the repsonse:%@",responseObject); + NSMutableArray* priorities = [[NSMutableArray alloc] init]; + + NSArray* dic = [responseObject objectForKey:@"issue_priorities"]; + for (NSDictionary* p in dic) { + [priorities addObject:[[OZLModelIssuePriority alloc] initWithDictionary:p]]; + } + block(priorities,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block([NSArray array], error); + } + }]; +} + +#pragma mark - +#pragma mark user api +// user ++(void)getUserListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block +{ + NSString* path = @"/users.json"; + NSMutableDictionary* paramsDic = [[NSMutableDictionary alloc] initWithDictionary:params]; + NSString* accessKey = [[OZLSingleton sharedInstance] redmineUserKey]; + if (accessKey.length > 0) { + [paramsDic setObject:accessKey forKey:@"key"]; + } + + [[OZLNetworkBase sharedClient] setAuthorizationHeader]; + [[OZLNetworkBase sharedClient] getPath:path parameters:paramsDic success:^(AFHTTPRequestOperation *operation, id responseObject) { + + if (block) { + NSLog(@"the repsonse:%@",responseObject); + NSMutableArray* priorities = [[NSMutableArray alloc] init]; + + NSArray* dic = [responseObject objectForKey:@"users"]; + for (NSDictionary* p in dic) { + [priorities addObject:[[OZLModelUser alloc] initWithDictionary:p]]; + } + block(priorities,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block([NSArray array], error); + } + }]; +} + + +#pragma mark - +#pragma mark issue status api +// issue status ++(void)getIssueStatusListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block +{ + NSString* path = @"/issue_statuses.json"; + NSMutableDictionary* paramsDic = [[NSMutableDictionary alloc] initWithDictionary:params]; + NSString* accessKey = [[OZLSingleton sharedInstance] redmineUserKey]; + if (accessKey.length > 0) { + [paramsDic setObject:accessKey forKey:@"key"]; + } + + [[OZLNetworkBase sharedClient] setAuthorizationHeader]; + [[OZLNetworkBase sharedClient] getPath:path parameters:paramsDic success:^(AFHTTPRequestOperation *operation, id responseObject) { + + if (block) { + NSLog(@"the repsonse:%@",responseObject); + NSMutableArray* priorities = [[NSMutableArray alloc] init]; + + NSArray* dic = [responseObject objectForKey:@"issue_statuses"]; + for (NSDictionary* p in dic) { + [priorities addObject:[[OZLModelIssueStatus alloc] initWithDictionary:p]]; + } + block(priorities,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block([NSArray array], error); + } + }]; +} + +#pragma mark - +#pragma mark tracker api +// tracker ++(void)getTrackerListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block +{ + NSString* path = @"/trackers.json"; + NSMutableDictionary* paramsDic = [[NSMutableDictionary alloc] initWithDictionary:params]; + NSString* accessKey = [[OZLSingleton sharedInstance] redmineUserKey]; + if (accessKey.length > 0) { + [paramsDic setObject:accessKey forKey:@"key"]; + } + + [[OZLNetworkBase sharedClient] setAuthorizationHeader]; + [[OZLNetworkBase sharedClient] getPath:path parameters:paramsDic success:^(AFHTTPRequestOperation *operation, id responseObject) { + + if (block) { + NSLog(@"the repsonse:%@",responseObject); + NSMutableArray* priorities = [[NSMutableArray alloc] init]; + + NSArray* dic = [responseObject objectForKey:@"trackers"]; + for (NSDictionary* p in dic) { + [priorities addObject:[[OZLModelTracker alloc] initWithDictionary:p]]; + } + block(priorities,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block([NSArray array], error); + } + }]; +} @end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.h b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.h index 9e3b41d..29125cc 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.h +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.h @@ -7,9 +7,27 @@ // #import +#import "OZLModelIssue.h" +#import "OZLModelProject.h" -@interface OZLIssueCreateViewController : UITableViewController +@interface OZLIssueCreateViewController : UITableViewController - (IBAction)onCancel:(id)sender; - (IBAction)onSave:(id)sender; +// neccessory +@property (weak, nonatomic) IBOutlet UITextField *subjectTextField; +@property (weak, nonatomic) IBOutlet UILabel *trackerLabel; +@property (weak, nonatomic) IBOutlet UILabel *statusLabel; +@property (weak, nonatomic) IBOutlet UILabel *priorityLabel; +// optional +@property (weak, nonatomic) IBOutlet UILabel *assigneeLabel; +@property (weak, nonatomic) IBOutlet UITextField *startDateLabel; +@property (weak, nonatomic) IBOutlet UITextField *dueDateLabel; +@property (weak, nonatomic) IBOutlet UITextField *estimatedHoursLabel; +@property (weak, nonatomic) IBOutlet UITextField *doneProgressLabel; +@property (weak, nonatomic) IBOutlet UITextView *descriptionTextview; + +@property(nonatomic,strong) OZLModelProject* parentProject; +@property(nonatomic,strong) OZLModelIssue* parentIssue; +@property(nonatomic,strong) NSArray* issueList; @end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m index e0800e3..d7fa966 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m @@ -7,8 +7,31 @@ // #import "OZLIssueCreateViewController.h" +#import "OZLNetwork.h" +#import "MBProgressHUD.h" +#import "OZLModelIssuePriority.h" +#import "OZLModelTracker.h" +#import "OZLModelUser.h" +#import "OZLModelIssueStatus.h" +#import "MLTableAlert.h" -@interface OZLIssueCreateViewController () +@interface OZLIssueCreateViewController () { + NSArray* _trackerList; + NSArray* _priorityList; + NSArray* _statusList; + NSArray* _userList; + + OZLModelTracker* _currentTracker; + OZLModelIssuePriority* _currentPriority; + OZLModelIssueStatus* _currentStatus; + OZLModelUser* _currentUser; + + NSDate* _currentStartDate; + NSDate* _currentDueDate; + int _currentEstimatedTime;//minutes + + MBProgressHUD* _HUD; +} @end @@ -32,6 +55,103 @@ UIBarButtonItem* saveBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(onSave:)]; [self.navigationItem setRightBarButtonItem:saveBtn]; + [self setupInputviews]; + + // hud + _HUD = [[MBProgressHUD alloc] initWithView:self.view]; + [self.view addSubview:_HUD]; + _HUD.labelText = @"Loading..."; + + [self loadIssueRelatedData]; +} + +-(void) setupInputviews +{ + // setup datapicker inputview + UIDatePicker* datePicker = [[UIDatePicker alloc]init]; + [datePicker setDatePickerMode:UIDatePickerModeDate]; + [datePicker addTarget:self action:@selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged]; + // accessoryview + UIToolbar* inputAccessoryView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 40)]; + UIBarButtonItem* accessoryDoneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(accessoryDoneClicked:)]; + UIBarButtonItem* flexleft = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]; + inputAccessoryView.items = [NSArray arrayWithObjects:flexleft, accessoryDoneButton, nil];; + + _startDateLabel.inputView = datePicker; + _startDateLabel.inputAccessoryView = inputAccessoryView; + _startDateLabel.delegate = self; + _dueDateLabel.inputView = datePicker; + _dueDateLabel.inputAccessoryView = inputAccessoryView; + _dueDateLabel.delegate = self; + + // setup time picker inputview + UIDatePicker* timerPicker = [[UIDatePicker alloc]init]; + [timerPicker setDatePickerMode:UIDatePickerModeCountDownTimer]; + [timerPicker addTarget:self action:@selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged]; + timerPicker.minuteInterval = 5; + _estimatedHoursLabel.inputView = timerPicker; + _estimatedHoursLabel.inputAccessoryView = inputAccessoryView; + _estimatedHoursLabel.delegate = self; + + // setup percentage pickerview + UIPickerView* percentageView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 320, 162)]; + percentageView.dataSource = self; + percentageView.delegate = self; + [percentageView selectRow:0 inComponent:0 animated:NO]; + _doneProgressLabel.inputView = percentageView; + _doneProgressLabel.inputAccessoryView = inputAccessoryView; + _doneProgressLabel.delegate = self; +} + +-(void)loadIssueRelatedData +{ + static int doneCount = 0; + [_HUD show:YES]; + [OZLNetwork getTrackerListWithParams:nil andBlock:^(NSArray *result, NSError *error) { + if (!error) { + _trackerList = result; + }else { + NSLog(@"get tracker list error : %@",error.description); + } + doneCount ++; + if (doneCount == 4) { + [_HUD hide:YES]; + } + }]; + + [OZLNetwork getIssueStatusListWithParams:nil andBlock:^(NSArray *result, NSError *error) { + if (!error) { + _statusList = result; + }else { + NSLog(@"get issue status list error : %@",error.description); + } + doneCount ++; + if (doneCount == 4) { + [_HUD hide:YES]; + } + }]; + [OZLNetwork getPriorityListWithParams:nil andBlock:^(NSArray *result, NSError *error) { + if (!error) { + _priorityList = result; + }else { + NSLog(@"get priority list error : %@",error.description); + } + doneCount ++; + if (doneCount == 4) { + [_HUD hide:YES]; + } + }]; + [OZLNetwork getUserListWithParams:nil andBlock:^(NSArray *result, NSError *error) { + if (!error) { + _userList = result; + }else { + NSLog(@"get user list error : %@",error.description); + } + doneCount ++; + if (doneCount == 4) { + [_HUD hide:YES]; + } + }]; } - (void)didReceiveMemoryWarning @@ -45,5 +165,237 @@ } - (IBAction)onSave:(id)sender { + + if (_subjectTextField.text.length == 0) { + _HUD.mode = MBProgressHUDModeText; + _HUD.labelText = @"subject can not be empty."; + [_HUD show:YES]; + [_HUD hide:YES afterDelay:1]; + return; + } + if (_currentUser == nil) { + _HUD.mode = MBProgressHUDModeText; + _HUD.labelText = @"tracker can not be empty."; + [_HUD show:YES]; + [_HUD hide:YES afterDelay:1]; + return; + } + if (_currentStatus == nil) { + _HUD.mode = MBProgressHUDModeText; + _HUD.labelText = @"status can not be empty."; + [_HUD show:YES]; + [_HUD hide:YES afterDelay:1]; + return; + } + if (_currentPriority == nil) { + _HUD.mode = MBProgressHUDModeText; + _HUD.labelText = @"priority can not be empty."; + [_HUD show:YES]; + [_HUD hide:YES afterDelay:1]; + return; + } + + OZLModelIssue* issueData = [[OZLModelIssue alloc] init]; + issueData.subject = _subjectTextField.text; + issueData.tracker = _currentTracker; + issueData.status = _currentStatus; + issueData.priority = _currentPriority; + issueData.assignedTo = _currentUser; + issueData.projectId = _parentProject.index; + + if (_parentIssue) { + issueData.parentIssueId = _parentIssue.index; + } + issueData.description = _descriptionTextview.text; + issueData.startDate = _startDateLabel.text; + issueData.dueDate = _dueDateLabel.text; + issueData.doneRatio = [_doneProgressLabel.text integerValue]; + issueData.estimatedHours = _currentEstimatedTime/60.0f; + //TODO: is_public is not processed yet + + + _HUD.mode = MBProgressHUDModeIndeterminate; + _HUD.labelText = @"Creating Project..."; + [_HUD show:YES]; + [OZLNetwork createIssue:issueData withParams:nil andBlock:^(BOOL success, NSError *error){ + if (error) { + NSLog(@"create project error: %@",error.description); + }else { + + } + [_HUD hide:YES]; + }]; + } + +- (void)viewDidUnload { + [self setSubjectTextField:nil]; + [self setTrackerLabel:nil]; + [self setStatusLabel:nil]; + [self setPriorityLabel:nil]; + [self setAssigneeLabel:nil]; + [self setStartDateLabel:nil]; + [self setDueDateLabel:nil]; + [self setEstimatedHoursLabel:nil]; + [self setDoneProgressLabel:nil]; + [self setDescriptionTextview:nil]; + [super viewDidUnload]; +} + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSArray* alertTitles = @[@"Select Tracker", @"Select Status", @"Select Priority", @"Select Assignee"]; + NSArray* dataArray = @[_trackerList, _statusList, _priorityList, _userList]; + if (indexPath.section == 1) { + + MLTableAlert* tableAlert = [MLTableAlert tableAlertWithTitle:[alertTitles objectAtIndex:indexPath.row] cancelButtonTitle:@"Cancel" numberOfRows:^NSInteger (NSInteger section) + { + return [[dataArray objectAtIndex:indexPath.row] count] + 1; + } + andCells:^UITableViewCell* (MLTableAlert *anAlert, NSIndexPath *alertIndexPath) + { + static NSString *CellIdentifier = @"CellIdentifier"; + UITableViewCell *cell = [anAlert.table dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; + + if (alertIndexPath.row == 0) { + cell.textLabel.text = @"None"; + }else { + cell.textLabel.text = [[[dataArray objectAtIndex:indexPath.row ]objectAtIndex:alertIndexPath.row - 1] name]; + } + return cell; + }]; + + // Setting custom alert height + tableAlert.height = 350; + + // configure actions to perform + [tableAlert configureSelectionBlock:^(NSIndexPath *selectedIndex){ + UITableViewCell* parentCell = [self.tableView cellForRowAtIndexPath:indexPath]; + if (selectedIndex.row == 0) { + switch (indexPath.row) { + case 0:{//tracker + _currentTracker = nil; + }break; + case 1:{//status + _currentStatus = nil; + }break; + case 2:{//priority + _currentPriority = nil; + }break; + case 3:{//assignee + _currentUser = nil; + }break; + default: + break; + } + + parentCell.detailTextLabel.text = @"None"; + }else { + id data = [[dataArray objectAtIndex:indexPath.row ] objectAtIndex:selectedIndex.row - 1]; + switch (indexPath.row) { + case 0:{//tracker + _currentUser = data; + }break; + case 1:{//status + _currentStatus = data; + }break; + case 2:{//priority + _currentPriority = data; + }break; + case 3:{//assignee + _currentUser = data; + }break; + + default: + break; + } + + parentCell.detailTextLabel.text = [data name]; + } + [parentCell.detailTextLabel sizeToFit]; + } andCompletionBlock:^{ + + }]; + + [tableAlert show]; + + }else if( indexPath.section == 2){ + switch (indexPath.row) { + case 0:{//start date + + }break; + case 1:{//due date + + }break; + case 2:{//estimated hours + + }break; + case 3:{//done + + }break; + + default: + break; + } + } + +} + +#pragma mark - +#pragma mark delegate of textfield inputview + + +#pragma mark data picker value changed +-(void)datePickerValueChanged:(id)sender +{ + UIDatePicker* datepicker = (UIDatePicker*)sender; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + + if (_estimatedHoursLabel.isFirstResponder) { + + NSString* timeStr = [NSString stringWithFormat:@"%d Mins",(int)datepicker.countDownDuration/60]; + _estimatedHoursLabel.text = timeStr; + _currentEstimatedTime = (int)datepicker.countDownDuration/60; + }else { + [dateFormatter setDateFormat:@"yyyy-MM-dd"]; + + NSString* dateStr = [dateFormatter stringFromDate:datepicker.date]; + if (_startDateLabel.isFirstResponder) { + _startDateLabel.text = dateStr; + _currentStartDate = datepicker.date; + }else if(_dueDateLabel.isFirstResponder) { + _dueDateLabel.text = dateStr; + _currentDueDate = datepicker.date; + } + } +} +-(void)accessoryDoneClicked:(id)sender +{ + [self.view endEditing:YES]; +} + +#pragma mark - +#pragma mark picker view delegate and datasource +- (void)pickerView:(UIPickerView *)pV didSelectRow:(NSInteger)row inComponent:(NSInteger)component +{ + _doneProgressLabel.text = [NSString stringWithFormat:@"%d %%",row * 10]; +} + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + return 1; +} + +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + return 11; +} + +- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + return [NSString stringWithFormat:@"%d %%",row * 10]; +} + @end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.storyboard b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.storyboard index 15f1ba0..2216f3e 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.storyboard +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.storyboard @@ -13,10 +13,10 @@ - + - + @@ -32,30 +32,12 @@ - - - - - - - - - - - - - - + + @@ -68,7 +50,7 @@ - - - + + @@ -93,7 +75,7 @@ - - - + + @@ -118,7 +100,7 @@ - - - + + @@ -143,7 +125,7 @@ - - - + + - - + + + + + + + + + + + + + + + + + + + + - - - + + - - - + + + + + + - + - - + + + + + + + @@ -267,21 +271,24 @@ + + + + + + + + + + + + - - - - - - - - - diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m index 1dac939..242ba90 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m @@ -41,8 +41,8 @@ _progressbar.progress = _issueData.doneRatio/100; _status.text = _issueData.status.name ; _priority.text = _issueData.priority.name; - _author.text = _issueData.author.name; - _assignedTo.text = _issueData.assignedTo.name; + _author.text = _issueData.author.login; + _assignedTo.text = _issueData.assignedTo.login; _startTime.text = _issueData.startDate; _dueTime.text = _issueData.dueDate; } diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectCreateViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectCreateViewController.m index cd2b951..9e389a4 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectCreateViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectCreateViewController.m @@ -112,7 +112,7 @@ // create the alert MLTableAlert* tableAlert = [MLTableAlert tableAlertWithTitle:@"Parent Project" cancelButtonTitle:@"Cancel" numberOfRows:^NSInteger (NSInteger section) { - return _projectList.count; + return _projectList.count + 1; } andCells:^UITableViewCell* (MLTableAlert *anAlert, NSIndexPath *indexPath) { diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m index 58194ab..fce4a94 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m @@ -251,7 +251,8 @@ - (IBAction)onNewIssue:(id)sender { //OZLIssueCreateViewController* creator = [[OZLIssueCreateViewController alloc] initWithNibName:@"OZLIssueCreateViewController" bundle:nil]; UIStoryboard *tableViewStoryboard = [UIStoryboard storyboardWithName:@"OZLIssueCreateViewController" bundle:nil]; - OZLIssueDetailViewController* creator = [tableViewStoryboard instantiateViewControllerWithIdentifier:@"OZLIssueCreateViewController"]; + OZLIssueCreateViewController* creator = [tableViewStoryboard instantiateViewControllerWithIdentifier:@"OZLIssueCreateViewController"]; + [creator setParentProject:_projectData]; //[self.navigationController presentModalViewController:creator animated:YES]; [self.navigationController pushViewController:creator animated:YES]; }