diff --git a/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj b/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj index 87d38a0..dd6ade0 100644 --- a/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj +++ b/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj @@ -25,11 +25,16 @@ 2B9968AB1794F71B0086F115 /* OZLModelIssueCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B9968AA1794F71B0086F115 /* OZLModelIssueCategory.m */; }; 2B9968AF1794FC0A0086F115 /* OZLProjectCreateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B9968AD1794FC0A0086F115 /* OZLProjectCreateViewController.m */; }; 2B9968B417951A5C0086F115 /* OZLIssueCreateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B9968B217951A5C0086F115 /* OZLIssueCreateViewController.m */; }; + 2BBE440F179E500E00FD9E20 /* OZLIssueLogtimeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BBE440E179E500E00FD9E20 /* OZLIssueLogtimeViewController.m */; }; + 2BBE4411179E503100FD9E20 /* OZLIssueLogtimeViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2BBE4410179E503100FD9E20 /* OZLIssueLogtimeViewController.storyboard */; }; + 2BBE4414179E586B00FD9E20 /* OZLModelTimeEntryActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BBE4413179E586B00FD9E20 /* OZLModelTimeEntryActivity.m */; }; 2BC4DD8C179928C80090F52C /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BC4DD8B179928C80090F52C /* SenTestingKit.framework */; }; 2BC4DD8D179928C80090F52C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB80591792F2BF0081662A /* UIKit.framework */; }; 2BC4DD8E179928C80090F52C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB805B1792F2BF0081662A /* Foundation.framework */; }; 2BC4DD94179928C80090F52C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2BC4DD92179928C80090F52C /* InfoPlist.strings */; }; 2BC4DD97179928C80090F52C /* RedmineMobileUnitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BC4DD96179928C80090F52C /* RedmineMobileUnitTest.m */; }; + 2BCBA81D179E292800E5FD46 /* OZLModelIssueJournal.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCBA81C179E292800E5FD46 /* OZLModelIssueJournal.m */; }; + 2BCBA820179E2AA500E5FD46 /* OZLModelIssueJournalDetail.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCBA81F179E2AA400E5FD46 /* OZLModelIssueJournalDetail.m */; }; 2BCC0FCF179D5458003DFB44 /* OZLIssueHistoryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCC0FCE179D5458003DFB44 /* OZLIssueHistoryViewController.m */; }; 2BCC0FD2179D56BA003DFB44 /* OZLModelTimeEntries.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCC0FD1179D56BA003DFB44 /* OZLModelTimeEntries.m */; }; 2BCCA0541795312E00FA8B1A /* OZLConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCCA0531795312E00FA8B1A /* OZLConstants.m */; }; @@ -113,6 +118,11 @@ 2B9968AD1794FC0A0086F115 /* OZLProjectCreateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLProjectCreateViewController.m; path = ViewControllers/OZLProjectCreateViewController.m; sourceTree = ""; }; 2B9968B117951A5C0086F115 /* OZLIssueCreateViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLIssueCreateViewController.h; path = ViewControllers/OZLIssueCreateViewController.h; sourceTree = ""; }; 2B9968B217951A5C0086F115 /* OZLIssueCreateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLIssueCreateViewController.m; path = ViewControllers/OZLIssueCreateViewController.m; sourceTree = ""; }; + 2BBE440D179E500E00FD9E20 /* OZLIssueLogtimeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLIssueLogtimeViewController.h; path = ViewControllers/OZLIssueLogtimeViewController.h; sourceTree = ""; }; + 2BBE440E179E500E00FD9E20 /* OZLIssueLogtimeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLIssueLogtimeViewController.m; path = ViewControllers/OZLIssueLogtimeViewController.m; sourceTree = ""; }; + 2BBE4410179E503100FD9E20 /* OZLIssueLogtimeViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = OZLIssueLogtimeViewController.storyboard; path = ViewControllers/OZLIssueLogtimeViewController.storyboard; sourceTree = ""; }; + 2BBE4412179E586B00FD9E20 /* OZLModelTimeEntryActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelTimeEntryActivity.h; path = Models/OZLModelTimeEntryActivity.h; sourceTree = ""; }; + 2BBE4413179E586B00FD9E20 /* OZLModelTimeEntryActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelTimeEntryActivity.m; path = Models/OZLModelTimeEntryActivity.m; sourceTree = ""; }; 2BC4DD8A179928C80090F52C /* RedmineMobileUnitTest.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RedmineMobileUnitTest.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 2BC4DD8B179928C80090F52C /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 2BC4DD91179928C80090F52C /* RedmineMobileUnitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RedmineMobileUnitTest-Info.plist"; sourceTree = ""; }; @@ -120,6 +130,10 @@ 2BC4DD95179928C80090F52C /* RedmineMobileUnitTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RedmineMobileUnitTest.h; sourceTree = ""; }; 2BC4DD96179928C80090F52C /* RedmineMobileUnitTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RedmineMobileUnitTest.m; sourceTree = ""; }; 2BC4DD98179928C80090F52C /* RedmineMobileUnitTest-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RedmineMobileUnitTest-Prefix.pch"; sourceTree = ""; }; + 2BCBA81B179E292800E5FD46 /* OZLModelIssueJournal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelIssueJournal.h; path = Models/OZLModelIssueJournal.h; sourceTree = ""; }; + 2BCBA81C179E292800E5FD46 /* OZLModelIssueJournal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelIssueJournal.m; path = Models/OZLModelIssueJournal.m; sourceTree = ""; }; + 2BCBA81E179E2AA400E5FD46 /* OZLModelIssueJournalDetail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelIssueJournalDetail.h; path = Models/OZLModelIssueJournalDetail.h; sourceTree = ""; }; + 2BCBA81F179E2AA400E5FD46 /* OZLModelIssueJournalDetail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLModelIssueJournalDetail.m; path = Models/OZLModelIssueJournalDetail.m; sourceTree = ""; }; 2BCC0FCD179D5458003DFB44 /* OZLIssueHistoryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLIssueHistoryViewController.h; path = ViewControllers/OZLIssueHistoryViewController.h; sourceTree = ""; }; 2BCC0FCE179D5458003DFB44 /* OZLIssueHistoryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OZLIssueHistoryViewController.m; path = ViewControllers/OZLIssueHistoryViewController.m; sourceTree = ""; }; 2BCC0FD0179D56BA003DFB44 /* OZLModelTimeEntries.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OZLModelTimeEntries.h; path = Models/OZLModelTimeEntries.h; sourceTree = ""; }; @@ -333,6 +347,9 @@ 2B62D0E71796A8D800AC3C19 /* OZLIssueFilterViewController.m */, 2BCC0FCD179D5458003DFB44 /* OZLIssueHistoryViewController.h */, 2BCC0FCE179D5458003DFB44 /* OZLIssueHistoryViewController.m */, + 2BBE440D179E500E00FD9E20 /* OZLIssueLogtimeViewController.h */, + 2BBE440E179E500E00FD9E20 /* OZLIssueLogtimeViewController.m */, + 2BBE4410179E503100FD9E20 /* OZLIssueLogtimeViewController.storyboard */, ); name = Issue; sourceTree = ""; @@ -514,6 +531,12 @@ 2B9968AA1794F71B0086F115 /* OZLModelIssueCategory.m */, 2BCC0FD0179D56BA003DFB44 /* OZLModelTimeEntries.h */, 2BCC0FD1179D56BA003DFB44 /* OZLModelTimeEntries.m */, + 2BCBA81B179E292800E5FD46 /* OZLModelIssueJournal.h */, + 2BCBA81C179E292800E5FD46 /* OZLModelIssueJournal.m */, + 2BCBA81E179E2AA400E5FD46 /* OZLModelIssueJournalDetail.h */, + 2BCBA81F179E2AA400E5FD46 /* OZLModelIssueJournalDetail.m */, + 2BBE4412179E586B00FD9E20 /* OZLModelTimeEntryActivity.h */, + 2BBE4413179E586B00FD9E20 /* OZLModelTimeEntryActivity.m */, ); name = Models; sourceTree = ""; @@ -617,6 +640,7 @@ 2B6F38341797A00A00D06F51 /* MLTableAlertButtonPressed@2x.png in Resources */, 2B6F38351797A00A00D06F51 /* MLTableAlertShadowMask.png in Resources */, 2B6F38361797A00A00D06F51 /* MLTableAlertShadowMask@2x.png in Resources */, + 2BBE4411179E503100FD9E20 /* OZLIssueLogtimeViewController.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -690,6 +714,10 @@ 2B6F38371797A00A00D06F51 /* MLTableAlert.m in Sources */, 2BCC0FCF179D5458003DFB44 /* OZLIssueHistoryViewController.m in Sources */, 2BCC0FD2179D56BA003DFB44 /* OZLModelTimeEntries.m in Sources */, + 2BCBA81D179E292800E5FD46 /* OZLModelIssueJournal.m in Sources */, + 2BCBA820179E2AA500E5FD46 /* OZLModelIssueJournalDetail.m in Sources */, + 2BBE440F179E500E00FD9E20 /* OZLIssueLogtimeViewController.m in Sources */, + 2BBE4414179E586B00FD9E20 /* OZLModelTimeEntryActivity.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssueCategory.m b/RedmineMobile/RedmineMobile/Models/OZLModelIssueCategory.m index cda8288..f6c37d9 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelIssueCategory.m +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssueCategory.m @@ -41,9 +41,9 @@ _name = [dic objectForKey:@"name"]; return self; } -//-(NSMutableDictionary*) toParametersDic -//{ -// -//} +-(NSMutableDictionary*) toParametersDic +{ + return nil; +} @end diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournal.h b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournal.h new file mode 100644 index 0000000..44fd59b --- /dev/null +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournal.h @@ -0,0 +1,66 @@ +// +// OZLModelIssueJournal.h +// RedmineMobile +// +// Created by lizhijie on 7/23/13. + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Zhijie Lee(onezeros.lee@gmail.com) +// +// 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 +#import "OZLModelUser.h" +#import "OZLModelIssueJournalDetail.h" + +/* + { + "id": 12353, + "user": { + "id": 20043, + "name": "wang lei" + }, + "notes": "fdfcasvawefqwf\r\n\r\nasdfasd\r\nasdfasdf", + "created_on": "2013-07-22T08:47:47Z", + "details": [ + { + "property": "attr", + "name": "done_ratio", + "old_value": "0", + "new_value": "20" + } + ] + } + + */ +@interface OZLModelIssueJournal : NSObject + +@property(nonatomic) int index; +@property(nonatomic, strong) NSString* notes; +@property(nonatomic, strong) NSString* createdOn; +@property(nonatomic, strong) OZLModelUser* user; +@property(nonatomic, strong) NSArray* detailArray; + +-(id)initWithDictionary:(NSDictionary*)dic; +-(NSMutableDictionary*) toParametersDic; + + +@end diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournal.m b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournal.m new file mode 100644 index 0000000..e6e4121 --- /dev/null +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournal.m @@ -0,0 +1,59 @@ +// +// OZLModelIssueJournal.m +// RedmineMobile +// +// Created by lizhijie on 7/23/13. + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Zhijie Lee(onezeros.lee@gmail.com) +// +// 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 "OZLModelIssueJournal.h" + +@implementation OZLModelIssueJournal + + +-(id)initWithDictionary:(NSDictionary*)dic +{ + self = [super init]; + if (!self) { + return nil; + } + _index = [[dic objectForKey:@"index"] intValue]; + _notes = [dic objectForKey:@"notes"]; + _createdOn = [dic objectForKey:@"created_on"]; + _user = [[ OZLModelUser alloc] initWithDictionary:[dic objectForKey:@"user"]]; + NSMutableArray* detailItems = [[NSMutableArray alloc] init]; + NSArray* dataArray = [dic objectForKey:@"details"]; + for (NSDictionary* detailDic in dataArray) { + [detailItems addObject:[[OZLModelIssueJournalDetail alloc] initWithDictionary:detailDic]]; + } + _detailArray = detailItems; + return self; + +} + +-(NSMutableDictionary*) toParametersDic +{ + return nil; +} + +@end diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournalDetail.h b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournalDetail.h new file mode 100644 index 0000000..3796584 --- /dev/null +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournalDetail.h @@ -0,0 +1,51 @@ +// +// OZLModelIssueJournalDetail.h +// RedmineMobile +// +// Created by lizhijie on 7/23/13. + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Zhijie Lee(onezeros.lee@gmail.com) +// +// 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 +/* + "details": [ + { + "property": "attr", + "name": "done_ratio", + "old_value": "0", + "new_value": "20" + } + ] + */ +@interface OZLModelIssueJournalDetail : NSObject + +@property(nonatomic, strong) NSString* property; +@property(nonatomic, strong) NSString* name; +@property(nonatomic, strong) NSString* oldValue; +@property(nonatomic, strong) NSString* freshValue; + +-(id)initWithDictionary:(NSDictionary*)dic; +-(NSMutableDictionary*) toParametersDic; + + +@end diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournalDetail.m b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournalDetail.m new file mode 100644 index 0000000..89b554c --- /dev/null +++ b/RedmineMobile/RedmineMobile/Models/OZLModelIssueJournalDetail.m @@ -0,0 +1,50 @@ +// +// OZLModelIssueJournalDetail.m +// RedmineMobile +// +// Created by lizhijie on 7/23/13. + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Zhijie Lee(onezeros.lee@gmail.com) +// +// 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 "OZLModelIssueJournalDetail.h" + +@implementation OZLModelIssueJournalDetail + +-(id)initWithDictionary:(NSDictionary*)dic +{ + self = [super init]; + if (!self) { + return nil; + } + _name = [dic objectForKey:@"name"]; + _property = [dic objectForKey:@"property"]; + _oldValue = [dic objectForKey:@"old_value"]; + _freshValue = [dic objectForKey:@"new_value"]; + return self; +} + +-(NSMutableDictionary*) toParametersDic +{ + return nil; +} +@end diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.h b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.h index 1a7786b..486c2f0 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.h +++ b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.h @@ -31,6 +31,7 @@ #import "OZLModelProject.h" #import "OZLModelIssue.h" #import "OZLModelUser.h" +#import "OZLModelTimeEntryActivity.h" @interface OZLModelTimeEntries : NSObject @@ -39,6 +40,7 @@ @property(nonatomic, strong) OZLModelProject* project; @property(nonatomic, strong) OZLModelUser* user; @property(nonatomic, strong) OZLModelIssue* issue; +@property(nonatomic, strong) OZLModelTimeEntryActivity* activity; @property(nonatomic) float hours; @property(nonatomic, strong) NSString* comments; @property(nonatomic, strong) NSString* spentOn; @@ -46,6 +48,7 @@ @property(nonatomic, strong) NSString* updatedOn; + -(id)initWithDictionary:(NSDictionary*)dic; -(NSMutableDictionary*) toParametersDic; diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.m b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.m index cfbdbd0..05edc7b 100644 --- a/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.m +++ b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntries.m @@ -38,9 +38,22 @@ return nil; } _index = [[dic objectForKey:@"id"] intValue]; - _project = [[OZLModelProject alloc] initWithDictionary:[dic objectForKey:@"project"]]; - _user = [[OZLModelUser alloc] initWithDictionary:[dic objectForKey:@"user"] ]; - _issue = [[OZLModelIssue alloc] initWithDictionary:[dic objectForKey:@"issue"]]; + id project = [dic objectForKey:@"project"]; + if (project != nil) { + _project = [[OZLModelProject alloc] initWithDictionary:project]; + } + id user = [dic objectForKey:@"user"]; + if (user != nil) { + _user = [[OZLModelUser alloc] initWithDictionary: user]; + } + id issue = [dic objectForKey:@"issue"]; + if (issue != nil ) { + _issue = [[OZLModelIssue alloc] initWithDictionary:issue]; + } + id activity = [dic objectForKey:@"activity"]; + if (activity != nil) { + _activity = [[OZLModelTimeEntryActivity alloc] initWithDictionary:activity]; + } _hours = [[dic objectForKey:@"hours"] floatValue]; _comments = [dic objectForKey:@"comments"]; _spentOn = [dic objectForKey:@"spent_on"]; @@ -51,7 +64,24 @@ -(NSMutableDictionary*) toParametersDic { - + NSMutableDictionary* entryDic = [[NSMutableDictionary alloc] init]; + [entryDic setObject:[NSNumber numberWithFloat:_hours] forKey:@"hours"];//required + if (_issue) { + [entryDic setObject:[NSNumber numberWithInt:_issue.index] forKey:@"issue_id"]; + }else if(_project){ + [entryDic setObject:[NSNumber numberWithInt:_project.index] forKey:@"project_id"]; + } + if (_spentOn) { + [entryDic setObject:_spentOn forKey:@"spent_on"]; + } + if (_activity) { + [entryDic setObject:[NSNumber numberWithInt:_activity.index] forKey:@"activity_id"]; + } + if (_comments) { + [entryDic setObject:_comments forKey:@"comments"]; + } + + return [[NSMutableDictionary alloc] initWithObjectsAndKeys:entryDic,@"time_entry",nil]; } diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntryActivity.h b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntryActivity.h new file mode 100644 index 0000000..0412aab --- /dev/null +++ b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntryActivity.h @@ -0,0 +1,39 @@ +// +// OZLModelTimeEntryActivity.h +// RedmineMobile +// +// Created by lizhijie on 7/23/13. + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Zhijie Lee(onezeros.lee@gmail.com) +// +// 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 OZLModelTimeEntryActivity : NSObject + +@property(nonatomic) int index; +@property(nonatomic,strong) NSString* name; + +-(id)initWithDictionary:(NSDictionary*)dic; +-(NSMutableDictionary*) toParametersDic; + +@end diff --git a/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntryActivity.m b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntryActivity.m new file mode 100644 index 0000000..d6401c2 --- /dev/null +++ b/RedmineMobile/RedmineMobile/Models/OZLModelTimeEntryActivity.m @@ -0,0 +1,48 @@ +// +// OZLModelTimeEntryActivity.m +// RedmineMobile +// +// Created by lizhijie on 7/23/13. + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright (c) 2013 Zhijie Lee(onezeros.lee@gmail.com) +// +// 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 "OZLModelTimeEntryActivity.h" + +@implementation OZLModelTimeEntryActivity +-(id)initWithDictionary:(NSDictionary*)dic +{ + self = [super init]; + if (!self) { + return nil; + } + _index = [[dic objectForKey:@"id"] intValue]; + _name = [dic objectForKey:@"name"]; + return self; +} + +-(NSMutableDictionary*) toParametersDic +{ + return nil; +} + +@end diff --git a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h index 19921ed..a1e3cbf 100644 --- a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h +++ b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.h @@ -33,6 +33,10 @@ #import "OZLModelIssueStatus.h" #import "OZLModelTracker.h" #import "OZLModelUser.h" +#import "OZLModelTimeEntries.h" +#import "OZLModelIssueJournal.h" +#import "OZLModelIssueJournalDetail.h" +#import "OZLModelTimeEntryActivity.h" @interface OZLNetwork : NSObject @@ -50,6 +54,7 @@ +(void)createIssue:(OZLModelIssue*)issueData withParams:(NSDictionary*)params andBlock:(void (^)(BOOL success, NSError *error))block; +(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; ++(void)getJournalListForIssue:(int)issueid withParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; // priority +(void)getPriorityListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; @@ -64,4 +69,8 @@ +(void)getTimeEntriesWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; +(void)getTimeEntriesForIssueId:(int)issueid withParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; +(void)getTimeEntriesForProjectId:(int)projectid withParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; ++(void)getTimeEntryListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block; ++(void)createTimeEntry:(OZLModelTimeEntries*)timeEntry withParams:(NSDictionary*)params andBlock:(void (^)(BOOL success, NSError *error))block; + + @end diff --git a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m index dfbc0f1..42ce7ea 100644 --- a/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m +++ b/RedmineMobile/RedmineMobile/Utils/OZLNetwork.m @@ -335,6 +335,37 @@ }]; } ++(void)getJournalListForIssue:(int)issueid withParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block +{ + NSString* path = [NSString stringWithFormat:@"/issues/%d.json?include=journals",issueid]; + NSMutableDictionary* paramsDic = [[NSMutableDictionary alloc] initWithDictionary:params]; + NSString* accessKey = [[OZLSingleton sharedInstance] redmineUserKey]; + if (accessKey.length > 0) { + [paramsDic setObject:accessKey forKey:@"key"]; + } + + [[OZLNetworkBase sharedClient] getPath:path parameters:paramsDic success:^(AFHTTPRequestOperation *operation, id responseObject) { + + if (block) { + NSLog(@"the repsonse:%@",responseObject); + + NSMutableArray* journals = [[NSMutableArray alloc] init]; + + NSArray* journalsDic = [[responseObject objectForKey:@"issue"] objectForKey:@"journals"]; + for (NSDictionary* p in journalsDic) { + [journals addObject:[[OZLModelIssueJournal alloc] initWithDictionary:p]]; + } + block(journals,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block([NSArray array], error); + } + + }]; +} #pragma mark - #pragma mark priority api @@ -495,7 +526,7 @@ NSArray* dic = [responseObject objectForKey:@"time_entries"]; for (NSDictionary* p in dic) { - [priorities addObject:[[OZLModelTracker alloc] initWithDictionary:p]]; + [priorities addObject:[[OZLModelTimeEntries alloc] initWithDictionary:p]]; } block(priorities,nil); } @@ -511,11 +542,75 @@ +(void)getTimeEntriesForIssueId:(int)issueid withParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block { - + NSDictionary* param = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:issueid],@"issue_id", nil]; + [OZLNetwork getTimeEntriesWithParams:param andBlock:block]; } +(void)getTimeEntriesForProjectId:(int)projectid withParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block { - + + NSDictionary* param = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:projectid],@"project_id", nil]; + [OZLNetwork getTimeEntriesWithParams:param andBlock:block]; } + ++(void)getTimeEntryListWithParams:(NSDictionary*)params andBlock:(void (^)(NSArray *result, NSError *error))block +{ + NSString* path = @"/enumerations/time_entry_activities.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* activities = [[NSMutableArray alloc] init]; + + NSArray* dic = [responseObject objectForKey:@"time_entry_activities"]; + for (NSDictionary* p in dic) { + [activities addObject:[[OZLModelTimeEntryActivity alloc] initWithDictionary:p]]; + } + block(activities,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block([NSArray array], error); + } + }]; +} ++(void)createTimeEntry:(OZLModelTimeEntries*)timeEntry withParams:(NSDictionary*)params andBlock:(void (^)(BOOL success, NSError *error))block +{ + NSString* path = [NSString stringWithFormat:@"/time_entries.json"]; + + //project info + NSMutableDictionary* paramsDic = [[NSMutableDictionary alloc] initWithDictionary:params]; + [paramsDic addEntriesFromDictionary:[timeEntry toParametersDic]]; + + NSString* accessKey = [[OZLSingleton sharedInstance] redmineUserKey]; + if (accessKey.length > 0) { + [paramsDic setObject:accessKey forKey:@"key"]; + } + + [[OZLNetworkBase sharedClient] postPath:path parameters:paramsDic success:^(AFHTTPRequestOperation *operation, id responseObject) { + + if (block) { + NSLog(@"the repsonse:%@",responseObject); + block(YES,nil); + } + + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + + if (block) { + block(NO, error); + } + + }]; +} + + @end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m index 2f75d9d..f9f3b95 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueCreateViewController.m @@ -90,7 +90,7 @@ 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];; + inputAccessoryView.items = [NSArray arrayWithObjects:flexleft, accessoryDoneButton, nil]; _startDateLabel.inputView = datePicker; _startDateLabel.inputAccessoryView = inputAccessoryView; @@ -288,16 +288,16 @@ }else if( indexPath.section == 2){ switch (indexPath.row) { case 0:{//start date - + [_startDateLabel becomeFirstResponder]; }break; case 1:{//due date - + [_dueDateLabel becomeFirstResponder]; }break; case 2:{//estimated hours - + [_estimatedHoursLabel becomeFirstResponder]; }break; case 3:{//done - + [_doneProgressLabel becomeFirstResponder]; }break; default: diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.h b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.h index a19d017..46430cb 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.h +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.h @@ -28,9 +28,13 @@ #import #import "OZLModelIssue.h" +#import "OZLModelTimeEntryActivity.h" @interface OZLIssueDetailViewController : UITableViewController -@property(nonatomic,strong) OZLModelIssue* issueData; + +@property(nonatomic, strong) OZLModelIssue* issueData; +@property(nonatomic, strong) NSArray* timeEntryActivityList; + @property (weak, nonatomic) IBOutlet UILabel *subject; @property (weak, nonatomic) IBOutlet UILabel *description; @property (weak, nonatomic) IBOutlet UIProgressView *progressbar; diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m index 7b77994..a91eaeb 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueDetailViewController.m @@ -27,6 +27,8 @@ // THE SOFTWARE. #import "OZLIssueDetailViewController.h" +#import "OZLIssueHistoryViewController.h" +#import "OZLIssueLogtimeViewController.h" @interface OZLIssueDetailViewController () @@ -81,16 +83,22 @@ { if (indexPath.section == 1) { switch (indexPath.row) { - case 0:{ - + case 0:{//history + OZLIssueHistoryViewController* history = [[OZLIssueHistoryViewController alloc] init]; + [history setIssueData:_issueData]; + [self.navigationController pushViewController:history animated:YES]; }break; - case 1:{ - + case 1:{// add sub task + }break; - case 2:{ - + case 2:{//logtime + UIStoryboard *tableViewStoryboard = [UIStoryboard storyboardWithName:@"OZLIssueLogtimeViewController" bundle:nil]; + OZLIssueLogtimeViewController* creator = [tableViewStoryboard instantiateViewControllerWithIdentifier:@"OZLIssueLogtimeViewController"]; + [creator setTimeEntryActivityList:_timeEntryActivityList]; + [creator setIssueData:_issueData]; + [self.navigationController pushViewController:creator animated:YES]; }break; - + default: break; } diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueHistoryViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueHistoryViewController.m index 8890ab8..22aab0a 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueHistoryViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueHistoryViewController.m @@ -28,8 +28,15 @@ #import "OZLIssueHistoryViewController.h" +#import "MBProgressHUD.h" +#import "OZLNetwork.h" +#import "OZLModelIssueJournal.h" +#import "OZLModelIssueJournalDetail.h" -@interface OZLIssueHistoryViewController () +@interface OZLIssueHistoryViewController () { + MBProgressHUD* _HUD; + NSMutableArray* _journalList; +} @end @@ -54,9 +61,27 @@ // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; + _HUD = [[MBProgressHUD alloc] initWithView:self.view]; + [self.view addSubview:_HUD]; + _HUD.labelText = @"Refreshing..."; + [self.navigationItem setTitle:_issueData.subject]; } + +-(void) viewWillAppear:(BOOL)animated +{ + [_HUD show:YES]; + // refresh journal list + [OZLNetwork getJournalListForIssue:_issueData.index withParams:nil andBlock:^(NSArray *result, NSError *error) { + NSLog(@"respond:%@",result.description); + _journalList = [[NSMutableArray alloc] initWithArray: result]; + [self.tableView reloadData]; + [_HUD hide:YES]; + }]; + +} + - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; @@ -67,78 +92,25 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { -#warning Potentially incomplete method implementation. - // Return the number of sections. - return 0; + return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { -#warning Incomplete method implementation. - // Return the number of rows in the section. - return 0; + return _journalList.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *CellIdentifier = @"Cell"; + static NSString *CellIdentifier = @"timeEntryCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; - - // Configure the cell... - + if (!cell) { + cell = [[UITableViewCell alloc] + initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; + } + OZLModelIssueJournal* journal = [_journalList objectAtIndex:indexPath.row]; + cell.textLabel.text = journal.user.name; return cell; } -/* -// Override to support conditional editing of the table view. -- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath -{ - // Return NO if you do not want the specified item to be editable. - return YES; -} -*/ - -/* -// Override to support editing the table view. -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (editingStyle == UITableViewCellEditingStyleDelete) { - // Delete the row from the data source - [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; - } - else if (editingStyle == UITableViewCellEditingStyleInsert) { - // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view - } -} -*/ - -/* -// Override to support rearranging the table view. -- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath -{ -} -*/ - -/* -// Override to support conditional rearranging of the table view. -- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath -{ - // Return NO if you do not want the item to be re-orderable. - return YES; -} -*/ - -#pragma mark - Table view delegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - // Navigation logic may go here. Create and push another view controller. - /* - <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil]; - // ... - // Pass the selected object to the new view controller. - [self.navigationController pushViewController:detailViewController animated:YES]; - */ -} - @end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.h b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.h new file mode 100644 index 0000000..c5fdb97 --- /dev/null +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.h @@ -0,0 +1,23 @@ +// +// OZLIssueLogtimeViewController.h +// RedmineMobile +// +// Created by lizhijie on 7/23/13. +// Copyright (c) 2013 Lee Zhijie. All rights reserved. +// + +#import +#import "OZLModelIssue.h" +#import "OZLModelTimeEntryActivity.h" + +@interface OZLIssueLogtimeViewController : UITableViewController + +@property (nonatomic, strong) OZLModelIssue* issueData; +@property (nonatomic, strong) NSArray* timeEntryActivityList; + +@property (weak, nonatomic) IBOutlet UITextField *hours; +@property (weak, nonatomic) IBOutlet UITextField *activity; +@property (weak, nonatomic) IBOutlet UITextField *dateLabel; +@property (weak, nonatomic) IBOutlet UITextView *comment; + +@end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.m new file mode 100644 index 0000000..375accb --- /dev/null +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.m @@ -0,0 +1,194 @@ +// +// OZLIssueLogtimeViewController.m +// RedmineMobile +// +// Created by lizhijie on 7/23/13. +// Copyright (c) 2013 Lee Zhijie. All rights reserved. +// + +#import "OZLIssueLogtimeViewController.h" +#import "MBProgressHUD.h" +#import "MLTableAlert.h" +#import "OZLNetwork.h" + +@interface OZLIssueLogtimeViewController () { + MBProgressHUD* _HUD; + float _hourValue; + OZLModelTimeEntries* _entry; +} +@end + +@implementation OZLIssueLogtimeViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // initialize data + _hourValue = 0; + _entry = [[OZLModelTimeEntries alloc] init]; + + UIBarButtonItem* cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onCancel:)]; + [self.navigationItem setLeftBarButtonItem:cancelBtn]; + UIBarButtonItem* saveBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(onSave:)]; + [self.navigationItem setRightBarButtonItem:saveBtn]; + + [self.navigationItem setTitle:@"Log Time"]; + + [self setupInputViews]; + + // hud + _HUD = [[MBProgressHUD alloc] initWithView:self.view]; + [self.view addSubview:_HUD]; + _HUD.labelText = @"Loading..."; +} + +-(void)setupInputViews +{ + [_activity setUserInteractionEnabled:NO]; + + // setup time picker inputview + UIDatePicker* timerPicker = [[UIDatePicker alloc]init]; + [timerPicker setDatePickerMode:UIDatePickerModeCountDownTimer]; + [timerPicker addTarget:self action:@selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged]; + timerPicker.minuteInterval = 5; + // 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]; + + _hours.inputView = timerPicker; + _hours.inputAccessoryView = inputAccessoryView; + _dateLabel.inputView = datePicker; + _dateLabel.inputAccessoryView = inputAccessoryView; +} +-(void) onCancel:(id)sender +{ + [self.navigationController popViewControllerAnimated:YES]; +} + +-(void) onSave:(id)sender +{ + _HUD.mode = MBProgressHUDModeIndeterminate; + _HUD.labelText = @"Logging time ..."; + [_HUD show:YES]; + + // build entry + _entry.issue = _issueData; + _entry.hours = _hourValue; + if (_comment.text.length > 0) { + _entry.comments = _comment.text; + } + if (_dateLabel.text.length > 0) { + _entry.createdOn = _dateLabel.text; + } + + [OZLNetwork createTimeEntry:_entry withParams:nil andBlock:^(BOOL success, NSError *error){ + if (error) { + NSLog(@"log time error: %@",error.description); + }else { + + [self.navigationController popViewControllerAnimated:YES]; + + } + [_HUD hide:YES]; + }]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.section == 0 && indexPath.row == 1) {//activity + MLTableAlert* tableAlert = [MLTableAlert tableAlertWithTitle:@"Activty" cancelButtonTitle:@"Cancel" numberOfRows:^NSInteger (NSInteger section) + { + return [_timeEntryActivityList 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 = [[_timeEntryActivityList objectAtIndex:alertIndexPath.row - 1] name]; + } + return cell; + }]; + + // Setting custom alert height + tableAlert.height = 350; + + // configure actions to perform + [tableAlert configureSelectionBlock:^(NSIndexPath *selectedIndex){ + if (selectedIndex.row == 0) { + _activity.text = @"None"; + _entry.activity = nil; + }else { + _activity.text = [[ _timeEntryActivityList objectAtIndex:selectedIndex.row - 1] name]; + _entry.activity = [_timeEntryActivityList objectAtIndex:selectedIndex.row -1]; + } + [_activity sizeToFit]; + } andCompletionBlock:^{ + + }]; + + [tableAlert show]; + } +} + +- (void)viewDidUnload { + [self setHours:nil]; + [self setActivity:nil]; + [self setDateLabel:nil]; + [self setComment:nil]; + [super viewDidUnload]; +} + +#pragma mark data picker value changed +-(void)datePickerValueChanged:(id)sender +{ + UIDatePicker* datepicker = (UIDatePicker*)sender; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + + if (_hours.isFirstResponder) { + + NSString* timeStr = [NSString stringWithFormat:@"%d Mins",(int)datepicker.countDownDuration/60]; + _hours.text = timeStr; + _hourValue = (int)(datepicker.countDownDuration/3600.f); + }else { + [dateFormatter setDateFormat:@"yyyy-MM-dd"]; + + NSString* dateStr = [dateFormatter stringFromDate:datepicker.date]; + _dateLabel.text = dateStr; + } +} + +-(void)accessoryDoneClicked:(id)sender +{ + [self.view endEditing:YES]; +} + +@end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.storyboard b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.storyboard new file mode 100644 index 0000000..14cef0d --- /dev/null +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLIssueLogtimeViewController.storyboard @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.h b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.h index 2fad8c6..24359da 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.h +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.h @@ -36,9 +36,10 @@ - (IBAction)onSortSetting:(id)sender; -@property (weak, nonatomic) NSArray* trackerList; -@property (weak, nonatomic) NSArray* priorityList; -@property (weak, nonatomic) NSArray* statusList; -@property (weak, nonatomic) NSArray* userList; +@property (strong, nonatomic) NSArray* trackerList; +@property (strong, nonatomic) NSArray* priorityList; +@property (strong, nonatomic) NSArray* statusList; +@property (strong, nonatomic) NSArray* userList; +@property (strong, nonatomic) NSArray* timeEntryActivityList; @end diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m index 3f576a1..75ef8e5 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m @@ -149,6 +149,7 @@ _issueListOption = [[NSMutableDictionary alloc] init]; static int doneCount = 0; + const int totalCount = 5; [OZLNetwork getTrackerListWithParams:nil andBlock:^(NSArray *result, NSError *error) { if (!error) { _trackerList = result; @@ -156,7 +157,7 @@ NSLog(@"get tracker list error : %@",error.description); } doneCount ++; - if (doneCount == 4) { + if (doneCount == totalCount) { [self loadProjectDetail]; doneCount = 0; } @@ -169,7 +170,7 @@ NSLog(@"get issue status list error : %@",error.description); } doneCount ++; - if (doneCount == 4) { + if (doneCount == totalCount) { [self loadProjectDetail]; doneCount = 0; } @@ -181,7 +182,7 @@ NSLog(@"get priority list error : %@",error.description); } doneCount ++; - if (doneCount == 4) { + if (doneCount == totalCount) { [self loadProjectDetail]; doneCount = 0; } @@ -193,7 +194,20 @@ NSLog(@"get user list error : %@",error.description); } doneCount ++; - if (doneCount == 4) { + if (doneCount == totalCount) { + [self loadProjectDetail]; + doneCount = 0; + } + }]; + + [OZLNetwork getTimeEntryListWithParams:nil andBlock:^(NSArray *result, NSError *error) { + if (!error) { + _timeEntryActivityList = result; + }else { + NSLog(@"get user list error : %@",error.description); + } + doneCount ++; + if (doneCount == totalCount) { [self loadProjectDetail]; doneCount = 0; } @@ -340,6 +354,7 @@ UIStoryboard *tableViewStoryboard = [UIStoryboard storyboardWithName:@"OZLIssueDetailViewController" bundle:nil]; OZLIssueDetailViewController* detail = [tableViewStoryboard instantiateViewControllerWithIdentifier:@"OZLIssueDetailViewController"]; [detail setIssueData:[_issuesList objectAtIndex:indexPath.row]]; + [detail setTimeEntryActivityList:_timeEntryActivityList]; [self.navigationController pushViewController:detail animated:YES]; }