diff --git a/Lemacs/Base.lproj/Main_iPhone.storyboard b/Lemacs/Base.lproj/Main_iPhone.storyboard
index ba8392d..04be6e8 100644
--- a/Lemacs/Base.lproj/Main_iPhone.storyboard
+++ b/Lemacs/Base.lproj/Main_iPhone.storyboard
@@ -17,8 +17,8 @@
-
-
+
+
@@ -35,11 +35,23 @@
+
+
+
+
+
+
+
+
+
-
+
+
+
+
@@ -67,6 +79,7 @@
+
@@ -79,6 +92,8 @@
+
+
@@ -92,16 +107,16 @@
-
+
-
+
-
+
@@ -144,17 +159,17 @@
-
+
-
+
-
+
@@ -212,6 +227,6 @@
-
+
\ No newline at end of file
diff --git a/Lemacs/GitHub/GHComment.h b/Lemacs/GitHub/GHComment.h
index 4a2c2f6..d6707fb 100644
--- a/Lemacs/GitHub/GHComment.h
+++ b/Lemacs/GitHub/GHComment.h
@@ -15,6 +15,7 @@
+ (instancetype)newCommentInContext:(NSManagedObjectContext *)context;
+ (instancetype)commentNumber:(NSInteger)commentNumber context:(NSManagedObjectContext *)context;
+@property (nonatomic) NSInteger commentID;
@property (nonatomic, strong) NSDate *createdDate;
@property (nonatomic, strong) NSString *body, *commentURL;
@property (nonatomic, strong) GHIssue *issue;
diff --git a/Lemacs/GitHub/GHComment.m b/Lemacs/GitHub/GHComment.m
index a6a9bf8..3e7d03b 100644
--- a/Lemacs/GitHub/GHComment.m
+++ b/Lemacs/GitHub/GHComment.m
@@ -7,6 +7,7 @@
//
#import "GHComment.h"
+#import "GHIssue.h"
#import "GHStore.h"
@implementation GHComment
@@ -54,10 +55,31 @@ + (NSString *)indexGitHubKey;
#pragma mark - API
-@dynamic body, commentURL, createdDate, issue, user;
+@dynamic body, commentID, commentURL, createdDate, issue, user;
@end
+
+@implementation GHComment (Deletion)
+
+- (IBAction)die;
+{ // ???: Can we do this? Should we do it after a delay? A request deletion method?
+ [[GHStore sharedStore] deleteComment:self];
+}
+
+@end
+
+
+@implementation GHComment (LETalk)
+
+- (NSString *)topic;
+{
+ return [self.issue currentValueForKey:kLETalkTitleKey];
+}
+
+@end
+
+
NSString * const kGHCommentEntityName = @"GHComment";
NSString * const kGHCommentIDGitHubKey = @"id";
diff --git a/Lemacs/GitHub/GHIssue.m b/Lemacs/GitHub/GHIssue.m
index 95f846d..2407bf9 100644
--- a/Lemacs/GitHub/GHIssue.m
+++ b/Lemacs/GitHub/GHIssue.m
@@ -10,6 +10,7 @@
#import "GHComment.h"
#import "GHStore.h"
+#import "GHUser.h"
#import "NSAttributedStringMarkdownParser+GHMarkdown.h"
@implementation GHIssue
@@ -128,6 +129,40 @@ - (IBAction)die;
@end
+@implementation GHIssue (LETalk)
+
+- (NSAttributedString *)styledTitle;
+{ // RealName (username) replied in|started topic
+ if (![self respondsToSelector:@selector(user)])
+ return nil;
+
+ GHUser *user = [self valueForKey:@"user"];
+
+ NSDictionary *boldBlackStyle = @{NSFontAttributeName : [UIFont boldSystemFontOfSize:10.0f],
+ NSForegroundColorAttributeName : [UIColor blackColor]};
+ NSDictionary *lightGrayStyle = @{NSFontAttributeName : [UIFont systemFontOfSize:10.0f],
+ NSForegroundColorAttributeName : [UIColor lightGrayColor]};
+
+ NSString *name = IsEmpty(user.displayName) ? user.userName : user.displayName;
+ if (!name)
+ name = NSLocalizedString(@"You", @"Second person pronoun");
+
+ NSMutableAttributedString *styledTitle = [[NSMutableAttributedString alloc] initWithString:name attributes:boldBlackStyle];
+
+ NSString *verb = [self isKindOfClass:[GHComment class]] ? NSLocalizedString(@" replied to ", @"reply verb") : NSLocalizedString(@" started ", @"initiate verb");
+ [styledTitle appendAttributedString:[[NSAttributedString alloc] initWithString:verb attributes:lightGrayStyle]];
+
+ return styledTitle;
+}
+
+- (NSString *)topic;
+{
+ return [self currentValueForKey:kLETalkTitleKey];
+}
+
+@end
+
+
NSString * const kGHIssueEntityName = @"GHIssue";
NSString * const kGHIssueClosedGitHubKey = @"state";
diff --git a/Lemacs/GitHub/GHManagedObject+LETalk.m b/Lemacs/GitHub/GHManagedObject+LETalk.m
index 53c1f90..34a055a 100644
--- a/Lemacs/GitHub/GHManagedObject+LETalk.m
+++ b/Lemacs/GitHub/GHManagedObject+LETalk.m
@@ -60,11 +60,6 @@ - (NSAttributedString *)styledBody;
return [[NSAttributedStringMarkdownParser sharedParser] attributedStringFromMarkdownString:NonNil(self.plainBody, @"")];
}
-- (NSString *)plainTitle;
-{
- return [self currentValueForKey:kLETalkTitleKey];
-}
-
- (NSAttributedString *)styledTitle;
{
if (![self respondsToSelector:@selector(user)])
@@ -87,5 +82,10 @@ - (NSAttributedString *)styledTitle;
return styledTitle;
}
+- (NSString *)topic;
+{
+ assert(NO); // Subclasses should override this
+ return [self currentValueForKey:kLETalkTitleKey];
+}
@end
diff --git a/Lemacs/GitHub/GHManagedObject.h b/Lemacs/GitHub/GHManagedObject.h
index fa947b0..cae69c3 100644
--- a/Lemacs/GitHub/GHManagedObject.h
+++ b/Lemacs/GitHub/GHManagedObject.h
@@ -19,6 +19,8 @@
@property (nonatomic, readonly) BOOL needsUpdating;
@property (nonatomic, strong) NSDate *lastUpdated;
+- (NSDictionary *)dictionaryWithValuesForGitHubKeys:(NSArray *)keys;
+
@end
diff --git a/Lemacs/GitHub/GHManagedObject.m b/Lemacs/GitHub/GHManagedObject.m
index 7bbf60a..855f986 100644
--- a/Lemacs/GitHub/GHManagedObject.m
+++ b/Lemacs/GitHub/GHManagedObject.m
@@ -98,27 +98,6 @@ - (void)setValue:(id)value forUndefinedKey:(NSString *)key;
[super setValue:value forUndefinedKey:key];
}
-- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
-{
- if (keys)
- return [super dictionaryWithValuesForKeys:keys];
-
- NSDictionary *GitHubKeysToPropertyNames = [[self class] GitHubKeysToPropertyNames];
- NSArray *GitHubKeys = GitHubKeysToPropertyNames.allKeys;
- __block NSMutableDictionary *GitHubKeysToCurrentValues = [NSMutableDictionary dictionaryWithCapacity:GitHubKeys.count];
- GHManagedObject * __weak currentObject = self;
- [GitHubKeys enumerateObjectsUsingBlock:^(NSString *GitHubKey, NSUInteger uselessIndex, BOOL *stop) {
- if ([GitHubKey isEqualToString:[[currentObject class] indexGitHubKey]])
- return;
-
- NSString *propertyName = [[self class] GitHubKeysToPropertyNames][GitHubKey];
- id propertyValue = [currentObject currentValueForKey:propertyName];
- [GitHubKeysToCurrentValues setValue:propertyValue forKey:GitHubKey];
- }];
-
- return [GitHubKeysToCurrentValues copy];
-}
-
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
{
NSDate *modifiedDate = keyedValues[kGHModifiedDatePropertyName];
@@ -270,6 +249,22 @@ - (BOOL)needsUpdating;
return -[self.lastUpdated timeIntervalSinceNow] > kGHStoreUpdateLimit;
}
+- (NSDictionary *)dictionaryWithValuesForGitHubKeys:(NSArray *)keys;
+{
+ __block NSMutableDictionary *GitHubKeysToCurrentValues = [NSMutableDictionary dictionaryWithCapacity:keys.count];
+ GHManagedObject * __weak currentObject = self;
+ [keys enumerateObjectsUsingBlock:^(NSString *GitHubKey, NSUInteger uselessIndex, BOOL *stop) {
+ if ([GitHubKey isEqualToString:[[currentObject class] indexGitHubKey]])
+ return;
+
+ NSString *propertyName = [[self class] GitHubKeysToPropertyNames][GitHubKey];
+ id propertyValue = [currentObject currentValueForKey:propertyName];
+ [GitHubKeysToCurrentValues setValue:propertyValue forKey:GitHubKey];
+ }];
+
+ return [GitHubKeysToCurrentValues copy];
+}
+
- (void)setUpRelationship:(NSRelationshipDescription *)relationship withValue:(id)value forKey:(NSString *)key;
{
if (relationship.isToMany)
diff --git a/Lemacs/GitHub/GHStore.h b/Lemacs/GitHub/GHStore.h
index 3c7ea50..80cd9cf 100644
--- a/Lemacs/GitHub/GHStore.h
+++ b/Lemacs/GitHub/GHStore.h
@@ -24,14 +24,14 @@
- (void)logInWithUsername:(NSString *)username password:(NSString *)password;
// Issues
-- (void)addIssue:(GHIssue *)issue;
-- (void)deleteIssue:(GHIssue *)issue;
- (void)loadIssues:(BOOL)freshStart;
- (void)loadCommentsForIssue:(GHIssue *)issue;
- (void)loadUser:(GHUser *)user;
-// Comments
-- (void)addComment:(GHComment *)comment toIssue:(GHIssue *)issue;
+// Saving
- (void)deleteComment:(GHComment *)comment;
+- (void)deleteIssue:(GHIssue *)issue;
+- (void)saveComment:(GHComment *)comment;
+- (void)saveIssue:(GHIssue *)issue;
@end
diff --git a/Lemacs/GitHub/GHStore.m b/Lemacs/GitHub/GHStore.m
index 71bd7fb..a270146 100644
--- a/Lemacs/GitHub/GHStore.m
+++ b/Lemacs/GitHub/GHStore.m
@@ -242,58 +242,11 @@ - (IBAction)sync;
// Scrub placeholder data
// ???: Can we push issues with comments already included?
-
- // Re-start sync
}
#pragma mark Loading
-- (void)addIssue:(GHIssue *)issue;
-{
- assert((IsEmpty(issue.body) && IsEmpty(issue.title))); // Otherwise defer to changeIssue:
- if (IsEmpty(issue.plainBody) || IsEmpty(issue.plainTitle))
- return; // Let the user know it's not ready yet or hide save button
-
- [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
-
- NSDictionary *valuesForGitHubKeys = [issue dictionaryWithValuesForKeys:nil];
- [self.GitHub addIssueForRepository:self.repositoryPath withDictionary:valuesForGitHubKeys success:^(id results) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- assert([results isKindOfClass:[NSArray class]]);
- NSDictionary *dictionary = [results lastObject];
- assert([results isKindOfClass:[NSDictionary class]]);
- [issue setValuesForKeysWithDictionary:dictionary];
- [[GHStore sharedStore] save];
- } failure:^(NSError *error) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- NSLog(@"Failure %@", error.localizedDescription);
- }];
-}
-
-- (void)deleteIssue:(GHIssue *)issue;
-{
- if (IsEmpty(issue.body)) {
- [issue.managedObjectContext deleteObject:issue];
- [self save];
- return ;
- }
-
- [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
-
- [self.GitHub deleteIssue:issue.number inRepository:self.repositoryPath success:^(BOOL success) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- if (!success)
- return; // ???: What does this state represent?
-
- [issue.managedObjectContext deleteObject:issue];
- [[GHStore sharedStore] save];
- } failure:^(NSError *error) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- NSLog(@"Failure %@", error.localizedDescription);
- }];
-}
-
- (void)loadIssues:(BOOL)freshStart;
{
if (freshStart)
@@ -349,8 +302,6 @@ - (void)loadCommentsForIssue:(GHIssue *)issue;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(@"%@ %@", NSStringFromSelector(_cmd), error.localizedDescription);
}];
-
- // [self.talkList reloadList];
}
- (void)loadUser:(GHUser *)user;
@@ -366,7 +317,7 @@ - (void)loadUser:(GHUser *)user;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
assert([results isKindOfClass:[NSArray class]]);
NSDictionary *dictionary = [results lastObject];
- assert([results isKindOfClass:[NSDictionary class]]);
+ assert([dictionary isKindOfClass:[NSDictionary class]]);
[user setValuesForKeysWithDictionary:dictionary];
[[GHStore sharedStore] save];
} failure:^(NSError *error) {
@@ -376,33 +327,124 @@ - (void)loadUser:(GHUser *)user;
}
-#pragma mark Comments
+#pragma mark Saving
+
+- (void)deleteComment:(GHComment *)comment;
+{
+ if (IsEmpty(comment.body)) {
+ [comment.managedObjectContext deleteObject:comment];
+ [self save];
+ return;
+ }
-- (void)addComment:(GHComment *)comment toIssue:(GHIssue *)issue;
+ [self saveComment:comment];
+}
+
+- (void)deleteIssue:(GHIssue *)issue;
{
- // TODO: clean up placeholder data
+ if (IsEmpty(issue.body)) {
+ [issue.managedObjectContext deleteObject:issue];
+ [self save];
+ return ;
+ }
+
+ [self saveIssue:issue];
+}
+- (void)saveComment:(GHComment *)comment;
+{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
- [self.GitHub addComment:comment.body toIssue:issue.number forRepository:self.repositoryPath success:^(id results) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- assert([results isKindOfClass:[NSArray class]]);
- NSLog(@"%@", results);
- NSDictionary *dictionary = [results lastObject];
- assert([results isKindOfClass:[NSDictionary class]]);
- [comment setValuesForKeysWithDictionary:dictionary];
- comment.changes = nil;
- NSLog(@"%@", dictionary);
- [[GHStore sharedStore] save];
- } failure:^(NSError *error) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- NSLog(@"%@ %@", NSStringFromSelector(_cmd), error.localizedDescription);
- }];
+ if (IsEmpty(comment.body) && !IsEmpty(comment.plainBody)) // Add
+ [self.GitHub addComment:comment.plainBody toIssue:comment.issue.number forRepository:self.repositoryPath success:^(id results) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ assert([results isKindOfClass:[NSArray class]]);
+ NSLog(@"%@", results);
+ NSDictionary *dictionary = [results lastObject];
+ assert([dictionary isKindOfClass:[NSDictionary class]]);
+ [comment setValuesForKeysWithDictionary:dictionary];
+ comment.changes = nil;
+ NSLog(@"%@", dictionary);
+ [[GHStore sharedStore] save];
+ } failure:^(NSError *error) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ NSLog(@"%@ %@", NSStringFromSelector(_cmd), error.localizedDescription);
+ }];
+ else if (!IsEmpty(comment.body) && !IsEmpty(comment.plainBody)) // Edit
+ [self.GitHub editComment:comment.commentID forRepository:self.repositoryPath withBody:comment.plainBody success:^(id results) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ assert([results isKindOfClass:[NSArray class]]);
+ NSLog(@"%@", results);
+ NSDictionary *dictionary = [results lastObject];
+ assert([dictionary isKindOfClass:[NSDictionary class]]);
+ [comment setValuesForKeysWithDictionary:dictionary];
+ comment.changes = nil;
+ NSLog(@"%@", dictionary);
+ [[GHStore sharedStore] save];
+ } failure:^(NSError *error) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ NSLog(@"%@ %@", NSStringFromSelector(_cmd), error.localizedDescription);
+ }];
+ else if (!IsEmpty(comment.body) && IsEmpty(comment.plainBody)) // Delete
+ [self.GitHub deleteComment:comment.commentID forRepository:self.repositoryPath success:^(BOOL buhweeted) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ if (buhweeted)
+ [comment.managedObjectContext deleteObject:comment];
+
+ [[GHStore sharedStore] save];
+ } failure:^(NSError *error) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ NSLog(@"%@ %@", NSStringFromSelector(_cmd), error.localizedDescription);
+ }];
+ else // Unhandled states
+ assert(NO);
}
-- (void)deleteComment:(GHComment *)comment;
+- (void)saveIssue:(GHIssue *)issue;
{
- // ???: Do we have to call validateForDelete: or is that involked automatically?
- [self.managedObjectContext deleteObject:comment];
+ if (IsEmpty(issue.topic)) { // Delete
+ [self.GitHub deleteIssue:issue.number inRepository:self.repositoryPath success:^(BOOL success) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ if (success)
+ [issue.managedObjectContext deleteObject:issue];
+
+ [[GHStore sharedStore] save];
+ } failure:^(NSError *error) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ NSLog(@"Failure %@", error.localizedDescription);
+ }];
+ return;
+ }
+
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
+ NSDictionary *valuesForGitHubKeys = [issue dictionaryWithValuesForGitHubKeys:@[kLETalkTitleKey, kLETalkBodyKey]];
+ if (IsEmpty(issue.title) && !IsEmpty(issue.plainBody)) // Add
+ [self.GitHub addIssueForRepository:self.repositoryPath withDictionary:valuesForGitHubKeys success:^(id results) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ assert([results isKindOfClass:[NSArray class]]);
+ NSDictionary *dictionary = [results lastObject];
+ assert([dictionary isKindOfClass:[NSDictionary class]]);
+ [issue setValuesForKeysWithDictionary:dictionary];
+ issue.changes = nil;
+ [[GHStore sharedStore] save];
+ } failure:^(NSError *error) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ NSLog(@"Failure %@", error.localizedDescription);
+ }];
+ else if (!IsEmpty(issue.body) && !IsEmpty(issue.plainBody)) // Edit
+ [self.GitHub editIssue:issue.number inRepository:self.repositoryPath withDictionary:valuesForGitHubKeys success:^(id results) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ assert([results isKindOfClass:[NSArray class]]);
+ NSDictionary *dictionary = [results lastObject];
+ assert([dictionary isKindOfClass:[NSDictionary class]]);
+ [issue setValuesForKeysWithDictionary:dictionary];
+ issue.changes = nil;
+ [[GHStore sharedStore] save];
+ } failure:^(NSError *error) {
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ NSLog(@"Failure %@", error.localizedDescription);
+ }];
+ else // Unhandled states
+ assert(NO);
}
@end
diff --git a/Lemacs/LETalk.h b/Lemacs/LETalk.h
index b434f3c..e2522a8 100644
--- a/Lemacs/LETalk.h
+++ b/Lemacs/LETalk.h
@@ -9,7 +9,7 @@
@protocol LETalk
@property (nonatomic, readonly) BOOL hasChanges;
@property (nonatomic, readonly) NSAttributedString *styledBody, *styledTitle;
-@property (nonatomic, readonly) NSString *bodyHTML, *displayedTime, *plainBody, *plainTitle;
+@property (nonatomic, readonly) NSString *bodyHTML, *displayedTime, *plainBody, *topic;
@property (nonatomic, readonly) NSURL *baseURL;
@property (nonatomic, readonly) UIImage *avatar;
@end
diff --git a/Lemacs/LETalkListController.m b/Lemacs/LETalkListController.m
index f1c89d5..9ff0239 100644
--- a/Lemacs/LETalkListController.m
+++ b/Lemacs/LETalkListController.m
@@ -92,7 +92,6 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
{
GHIssue *issue;
if ([[segue identifier] isEqualToString:@"CreateIssue"]) {
- // Create issue
issue = [GHIssue newIssueInContext:self.managedObjectContext];
assert([segue.destinationViewController isKindOfClass:[LEWorkViewController class]]);
[[segue destinationViewController] setTalk:issue];
@@ -111,7 +110,7 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
assert([segue.destinationViewController isKindOfClass:[LETalkViewController class]]);
LETalkViewController *talkViewController = (LETalkViewController *)segue.destinationViewController;
talkViewController.issue = issue;
- talkViewController.navigationItem.prompt = issue.plainTitle;
+ talkViewController.navigationItem.prompt = issue.topic;
} else if ([[segue identifier] isEqualToString:@"SelectTalk"]) {
assert([segue.destinationViewController isKindOfClass:[LEWorkViewController class]]);
[[segue destinationViewController] setTalk:issue];
@@ -393,8 +392,10 @@ - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPa
NSInteger commentsCount = issue.commentsCount;
if (commentsCount) {
talkCell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
+ talkCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"TalkDisclosure"]];
} else {
- talkCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+ talkCell.accessoryType = UITableViewCellAccessoryNone;
+ talkCell.accessoryView = nil;
}
}
diff --git a/Lemacs/LETalkViewController.h b/Lemacs/LETalkViewController.h
index 52045c9..92a96b6 100644
--- a/Lemacs/LETalkViewController.h
+++ b/Lemacs/LETalkViewController.h
@@ -12,7 +12,6 @@
@property (strong, nonatomic) GHIssue *issue;
-- (IBAction)reloadList;
- (IBAction)sortList:(UISegmentedControl *)sortControl;
@end
diff --git a/Lemacs/LETalkViewController.m b/Lemacs/LETalkViewController.m
index 7afc43f..f6e81e9 100644
--- a/Lemacs/LETalkViewController.m
+++ b/Lemacs/LETalkViewController.m
@@ -26,6 +26,7 @@ @interface LETalkViewController ()
@property (nonatomic) BOOL reverseSort;
- (IBAction)insertNewObject;
+- (IBAction)reloadList;
- (IBAction)saveContext;
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
@@ -40,6 +41,7 @@ + (void)initialize;
[[NSUserDefaults standardUserDefaults] registerDefaults:@{kLETalkViewSortOrder : @(NO)}];
}
+
#pragma mark - NSObject (UINibLoadingAdditions)
- (void)awakeFromNib;
@@ -59,8 +61,15 @@ - (void)viewDidLoad;
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([LETalkCell class]) bundle:nil] forCellReuseIdentifier:NSStringFromClass([LETalkCell class])];
+}
+- (void)viewWillAppear:(BOOL)animated;
+{
self.reverseSort = [[NSUserDefaults standardUserDefaults] integerForKey:kLETalkViewSortOrder];
+
+ [self reloadList];
+
+ [super viewWillAppear:animated];
}
- (void)didReceiveMemoryWarning;
@@ -74,13 +83,19 @@ - (void)didReceiveMemoryWarning;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
{
+ id talk;
+
if ([[segue identifier] isEqualToString:@"SelectTalk"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
- id talk = (indexPath.section < self.fetchedResultsController.sections.count) ? [self.fetchedResultsController objectAtIndexPath:indexPath] : self.issue;
+ talk = (indexPath.section < self.fetchedResultsController.sections.count) ? [self.fetchedResultsController objectAtIndexPath:indexPath] : self.issue;
assert([talk conformsToProtocol:@protocol(LETalk)]);
- assert([segue.destinationViewController isKindOfClass:[LEWorkViewController class]]);
- [[segue destinationViewController] setTalk:talk];
- }
+ } else if ([[segue identifier] isEqualToString:@"CreateComment"])
+ talk = [self.issue addComment];
+ else
+ assert(NO);
+
+ assert([segue.destinationViewController isKindOfClass:[LEWorkViewController class]]);
+ [[segue destinationViewController] setTalk:talk];
}
diff --git a/Lemacs/LEWorkViewController.h b/Lemacs/LEWorkViewController.h
index 2641f19..79793d2 100644
--- a/Lemacs/LEWorkViewController.h
+++ b/Lemacs/LEWorkViewController.h
@@ -8,13 +8,15 @@
#import "LETalk.h"
-@interface LEWorkViewController : UIViewController
+@interface LEWorkViewController : UIViewController
+@property (nonatomic, weak) IBOutlet UITextField *topicField;
@property (nonatomic, weak) IBOutlet UITextView *textView;
@property (nonatomic, weak) IBOutlet UISegmentedControl *segmentedControl;
@property (strong, nonatomic) id talk;
- (IBAction)cancel;
+- (IBAction)delete;
- (IBAction)reply;
- (IBAction)save;
- (IBAction)togglePreview:(UISegmentedControl *)segmentedControl;
diff --git a/Lemacs/LEWorkViewController.m b/Lemacs/LEWorkViewController.m
index 6f1d13c..7aacd4e 100644
--- a/Lemacs/LEWorkViewController.m
+++ b/Lemacs/LEWorkViewController.m
@@ -61,6 +61,32 @@ - (void)splitViewController:(UISplitViewController *)splitController willShowVie
}
+#pragma mark - UITextFieldDelegate
+
+- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
+{
+ if (IsEmpty(textField.text) && !IsEmpty(string))
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(save)];
+ else if (!IsEmpty(textField.text) && IsEmpty([textField.text stringByReplacingCharactersInRange:range withString:string]))
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(delete)];
+
+ return YES;
+}
+
+- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
+{
+ return [self.talk isKindOfClass:[GHIssue class]];
+}
+
+- (void)textFieldDidEndEditing:(UITextField *)textField;
+{
+ GHIssue *issue = (GHIssue *)self.talk;
+ assert([self.talk isKindOfClass:[GHIssue class]]);
+ [issue setChangeValue:textField.text forPropertyNamed:kLETalkTitleKey];
+ [[GHStore sharedStore] save];
+}
+
+
#pragma mark - UITextViewDelegate
- (void)textViewDidBeginEditing:(UITextView *)textView;
@@ -80,11 +106,13 @@ - (void)textViewDidChange:(UITextView *)textView;
GHManagedObject *editedObject = (GHManagedObject *)self.talk;
assert([editedObject isKindOfClass:[GHManagedObject class]]);
- if (!self.talk.plainBody.length && textView.text.length)
+ if (!self.talk.plainBody.length && textView.text.length) {
self.navigationItem.leftBarButtonItem = nil;
- else if (!textView.text.length && self.talk.plainBody.length)
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(save)];
+ } else if (!textView.text.length && self.talk.plainBody.length) {
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)];
-
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(delete)];
+ }
[editedObject setChangeValue:textView.text forPropertyNamed:kLETalkBodyKey];
}
@@ -98,8 +126,21 @@ - (void)setEditing:(BOOL)editing;
self.textView.editable = editing;
self.textView.font = [UIFont markdownParagraphFont]; // To clear style
+ super.editing = editing;
+
+ if ([self.talk isKindOfClass:[GHIssue class]] && editing) {
+ self.navigationItem.prompt = nil;
+ self.topicField.hidden = NO;
+ self.topicField.text = self.talk.topic;
+ } else {
+ self.navigationItem.prompt = self.talk.topic;
+ self.topicField.hidden = YES;
+ self.topicField.text = nil;
+ }
if (editing) {
+ self.segmentedControl.selectedSegmentIndex = 1;
+ [self.textView becomeFirstResponder];
self.textView.text = self.talk.plainBody;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(save)];
if (!self.talk.hasChanges || (!self.talk.plainBody.length && !self.textView.text.length))
@@ -107,13 +148,14 @@ - (void)setEditing:(BOOL)editing;
else
self.navigationItem.leftBarButtonItem = nil;
} else {
+ self.segmentedControl.selectedSegmentIndex = 0;
+ [self.textView resignFirstResponder];
self.textView.attributedText = self.talk.styledBody;
- self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:self action:@selector(reply)];
- self.navigationItem.leftBarButtonItem = nil;
+ if (!self.talk.hasChanges) {
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:self action:@selector(reply)];
+ self.navigationItem.leftBarButtonItem = nil;
+ }
}
-
- super.editing = editing;
- [self.textView becomeFirstResponder];
}
- (void)setTalk:(id )talk;
@@ -122,7 +164,7 @@ - (void)setTalk:(id )talk;
return;
_talk = talk;
-
+
[self configureView];
}
@@ -140,8 +182,7 @@ - (IBAction)cancel;
BOOL delete = isEmpty && isNew;
BOOL revert = isEmpty && !isNew;
- if (delete) { // Otherwise, you have to kill it from the list.
- // In the future, we can
+ if (delete) {
GHManagedObject *doomedObject = (GHManagedObject *)self.talk;
assert([doomedObject isKindOfClass:[GHManagedObject class]]);
self.talk = nil;
@@ -157,6 +198,18 @@ - (IBAction)cancel;
[self.navigationController popViewControllerAnimated:YES];
}
+- (IBAction)delete;
+{
+ self.editing = NO;
+ if ([self.talk isKindOfClass:[GHIssue class]]) {
+ [[GHStore sharedStore] saveIssue:(GHIssue *)self.talk];
+ [self.navigationController popToRootViewControllerAnimated:YES];
+ } else if ([self.talk isKindOfClass:[GHComment class]]) {
+ [[GHStore sharedStore] saveComment:(GHComment *)self.talk];
+ [self.navigationController popViewControllerAnimated:YES];
+ }
+}
+
- (IBAction)reply;
{
GHIssue *issue;
@@ -173,10 +226,18 @@ - (IBAction)reply;
- (IBAction)save;
{
NSLog(@"%@", NSStringFromSelector(_cmd));
- // If new
- // Commit and sync
- // else
- // Show commit screen
+ assert(!IsEmpty(self.talk.plainBody) && self.talk.hasChanges); // Otherwise the save button shouldn't be available.
+
+ // Save it locally, start the server push
+ [[GHStore sharedStore] sync];
+
+ self.editing = NO;
+ if ([self.talk isKindOfClass:[GHIssue class]])
+ [[GHStore sharedStore] saveIssue:(GHIssue *)self.talk];
+ else if ([self.talk isKindOfClass:[GHComment class]])
+ [[GHStore sharedStore] saveComment:(GHComment *)self.talk];
+
+ [self.navigationController popViewControllerAnimated:YES];
}
- (IBAction)togglePreview:(UISegmentedControl *)segmentedControl;
@@ -188,10 +249,10 @@ - (void)configureView;
{
if (!self.talk)
return; // This should only happen while the controller is still being set up
+ // It also happens during cancel
// Default to editing mode if this is an uncommited talk
self.editing = IsEmpty([(NSObject *)self.talk valueForKey:kLETalkBodyKey]) || self.talk.hasChanges;
- self.navigationItem.prompt = self.talk.plainTitle;
self.segmentedControl.selectedSegmentIndex = self.editing ? 1 : 0;
}