[from now] 2012/09/03 01:38:22

diff --git a/skooma.xcodeproj/project.pbxproj b/skooma.xcodeproj/project.pbxproj
index 3e6f952..4d4c218 100644
--- a/skooma.xcodeproj/project.pbxproj
+++ b/skooma.xcodeproj/project.pbxproj
@@ -18,6 +18,7 @@
 		426516FB15E3F71C00B36104 /* CCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 426516FA15E3F71C00B36104 /* CCAppDelegate.m */; };
 		4275125E15F3493B0025B046 /* NSURLRequest+Custom.m in Sources */ = {isa = PBXBuildFile; fileRef = 4275125D15F3493B0025B046 /* NSURLRequest+Custom.m */; };
 		4275126115F3495C0025B046 /* UIView+Custom.m in Sources */ = {isa = PBXBuildFile; fileRef = 4275126015F3495C0025B046 /* UIView+Custom.m */; };
+		4275128C15F3A8AE0025B046 /* CCSwipableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4275128B15F3A8AE0025B046 /* CCSwipableCell.m */; };
 		42B6C7D915F2248700C80CC4 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42B6C7D815F2248700C80CC4 /* SystemConfiguration.framework */; };
 		42B6C7E215F2297100C80CC4 /* CCThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 42B6C7E115F2297100C80CC4 /* CCThreadViewController.m */; };
 		42B6C7E515F22A3400C80CC4 /* CCThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 42B6C7E415F22A3400C80CC4 /* CCThread.m */; };
@@ -43,6 +44,8 @@
 		4275125D15F3493B0025B046 /* NSURLRequest+Custom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLRequest+Custom.m"; sourceTree = "<group>"; };
 		4275125F15F3495C0025B046 /* UIView+Custom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Custom.h"; sourceTree = "<group>"; };
 		4275126015F3495C0025B046 /* UIView+Custom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Custom.m"; sourceTree = "<group>"; };
+		4275128A15F3A8AE0025B046 /* CCSwipableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCSwipableCell.h; sourceTree = "<group>"; };
+		4275128B15F3A8AE0025B046 /* CCSwipableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCSwipableCell.m; sourceTree = "<group>"; };
 		42B6C7D815F2248700C80CC4 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
 		42B6C7E015F2297100C80CC4 /* CCThreadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCThreadViewController.h; sourceTree = "<group>"; };
 		42B6C7E115F2297100C80CC4 /* CCThreadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCThreadViewController.m; sourceTree = "<group>"; };
@@ -125,6 +128,8 @@
 				42B6C7E415F22A3400C80CC4 /* CCThread.m */,
 				4221382515F24D990088B119 /* CCThreadCell.h */,
 				4221382615F24D990088B119 /* CCThreadCell.m */,
+				4275128A15F3A8AE0025B046 /* CCSwipableCell.h */,
+				4275128B15F3A8AE0025B046 /* CCSwipableCell.m */,
 				42B6C7E015F2297100C80CC4 /* CCThreadViewController.h */,
 				42B6C7E115F2297100C80CC4 /* CCThreadViewController.m */,
 				426516F115E3F71C00B36104 /* Supporting Files */,
@@ -222,6 +227,7 @@
 				4221382715F24D990088B119 /* CCThreadCell.m in Sources */,
 				4275125E15F3493B0025B046 /* NSURLRequest+Custom.m in Sources */,
 				4275126115F3495C0025B046 /* UIView+Custom.m in Sources */,
+				4275128C15F3A8AE0025B046 /* CCSwipableCell.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/skooma/CCSwipableCell.h b/skooma/CCSwipableCell.h
new file mode 100644
index 0000000..7466060
--- /dev/null
+++ b/skooma/CCSwipableCell.h
@@ -0,0 +1,40 @@
+//
+//  CCSwipableCell.h
+//  skooma
+//
+//  Created by cc on 2012/09/02.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+@class CCSwipableCell;
+
+typedef enum {
+    SwipeDirectionRight = 0,
+    SwipeDirectionLeft,
+    SwipeDirectionBoth,
+    SwipeDirectionNone,
+} CCSwipeDirection;
+
+@protocol CCSwipableCellDelegate <NSObject>
+- (void)cellDidReceiveSwipe:(CCSwipableCell *)cell;
+
+@end
+
+
+
+
+
+@interface CCSwipableCell : UITableViewCell
+
+@property (nonatomic) id <CCSwipableCellDelegate> delegate;
+@property (nonatomic) CCSwipeDirection swipeDirection;
+@property (nonatomic) UISwipeGestureRecognizer *lastGestureRecognized;
+
+- (void)slideOutContentView;
+- (void)slideInContentView;
+
+@end
+
+
diff --git a/skooma/CCSwipableCell.m b/skooma/CCSwipableCell.m
new file mode 100644
index 0000000..f24a2bd
--- /dev/null
+++ b/skooma/CCSwipableCell.m
@@ -0,0 +1,135 @@
+//
+//  CCSwipableCell.m
+//  skooma
+//
+//  Created by cc on 2012/09/02.
+//
+//
+
+#import "CCSwipableCell.h"
+
+@interface CCSwipableCell ()
+- (void)addSwipeGestureRecognizer:(UISwipeGestureRecognizerDirection)direction;
+@end
+
+@implementation CCSwipableCell
+
+- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
+{
+    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
+    if (self) {
+        self.swipeDirection = SwipeDirectionRight;
+
+        UIView *defaultBackgroundView = [[UIView  alloc] initWithFrame:self.contentView.frame];
+        defaultBackgroundView.backgroundColor = [UIColor darkGrayColor];
+        self.backgroundView = defaultBackgroundView;
+    }
+    return self;
+}
+
+- (void)handleSwipe:(UISwipeGestureRecognizer *)gesture
+{
+    _lastGestureRecognized = gesture;
+    [self slideOutContentView];
+    [_delegate cellDidReceiveSwipe:self];
+}
+
+- (void)setSwipeDirection:(CCSwipeDirection)direction
+{
+    _swipeDirection = direction;
+
+    NSArray *existingGestures = [self gestureRecognizers];
+    for (UIGestureRecognizer *gesture in existingGestures) {
+        [self removeGestureRecognizer:gesture];
+    }
+
+    switch (_swipeDirection) {
+        case SwipeDirectionLeft:
+            [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionLeft];
+            break;
+        case SwipeDirectionRight:
+            [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionRight];
+            break;
+        case SwipeDirectionBoth:
+            [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionLeft];
+            [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionRight];
+        default:
+            break;
+    }
+}
+
+- (void)addSwipeGestureRecognizer:(UISwipeGestureRecognizerDirection)direction;
+{
+    UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
+    swipeGesture.direction = direction;
+    [self addGestureRecognizer:swipeGesture];
+}
+
+
+#pragma mark Sliding content view
+
+#define kBOUNCE_DISTANCE 20.0
+
+void LR_offsetView(UIView *view, CGFloat offsetX, CGFloat offsetY)
+{
+    view.frame = CGRectOffset(view.frame, offsetX, offsetY);
+}
+
+- (void)slideOutContentView;
+{
+    CGFloat offsetX;
+
+    switch (_lastGestureRecognized.direction) {
+        case UISwipeGestureRecognizerDirectionLeft:
+            offsetX = -self.contentView.frame.size.width;
+            break;
+        case UISwipeGestureRecognizerDirectionRight:
+            offsetX = self.contentView.frame.size.width;
+            break;
+        default:
+            @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Unhandled gesture direction" userInfo:[NSDictionary dictionaryWithObject:self.lastGestureRecognized forKey:@"lastGestureRecognized"]];
+            break;
+    }
+
+    [UIView animateWithDuration:0.2
+                          delay:0
+                        options:UIViewAnimationOptionCurveEaseOut
+                     animations:^{ LR_offsetView(self.contentView, offsetX, 0); }
+                     completion:NULL];
+}
+
+- (void)slideInContentView;
+{
+    CGFloat offsetX, bounceDistance;
+
+    switch (self.lastGestureRecognized.direction) {
+        case UISwipeGestureRecognizerDirectionLeft:
+            offsetX = self.contentView.frame.size.width;
+            bounceDistance = -kBOUNCE_DISTANCE;
+            break;
+        case UISwipeGestureRecognizerDirectionRight:
+            offsetX = -self.contentView.frame.size.width;
+            bounceDistance = kBOUNCE_DISTANCE;
+            break;
+        default:
+            @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Unhandled gesture direction" userInfo:[NSDictionary dictionaryWithObject:self.lastGestureRecognized forKey:@"lastGestureRecognized"]];
+            break;
+    }
+
+    [UIView animateWithDuration:0.1 delay:0
+                        options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAllowUserInteraction
+                     animations:^{ LR_offsetView(self.contentView, offsetX, 0); }
+                     completion:^(BOOL f) {
+                         [UIView animateWithDuration:0.1 delay:0
+                                             options:UIViewAnimationCurveLinear
+                                          animations:^{ LR_offsetView(self.contentView, bounceDistance, 0); }
+                                          completion:^(BOOL f) {
+                                              [UIView animateWithDuration:0.1 delay:0
+                                                                  options:UIViewAnimationCurveLinear
+                                                               animations:^{ LR_offsetView(self.contentView, -bounceDistance, 0); }
+                                                               completion:NULL];
+                                          }];
+                     }];
+}
+
+@end
diff --git a/skooma/CCThreadViewController.h b/skooma/CCThreadViewController.h
index f61f5ed..59c54d6 100644
--- a/skooma/CCThreadViewController.h
+++ b/skooma/CCThreadViewController.h
@@ -8,8 +8,9 @@

 #import <UIKit/UIKit.h>
 #import "CCThread.h"
+#import "CCSwipableCell.h"

-@interface CCThreadViewController : UITableViewController <NSURLConnectionDataDelegate>
+@interface CCThreadViewController : UITableViewController <NSURLConnectionDataDelegate, CCSwipableCellDelegate>

diff --git a/skooma/CCThreadViewController.m b/skooma/CCThreadViewController.m
index 92d1f08..62805ad 100644
--- a/skooma/CCThreadViewController.m
+++ b/skooma/CCThreadViewController.m
@@ -18,6 +18,9 @@
 @property (nonatomic) NSHTTPURLResponse *response;
 @property (nonatomic) NSMutableData *buffer;

+@property (nonatomic) CCSwipableCell *currentlyActiveSlidingCell;
+@property (nonatomic) CCSwipeDirection swipeDirection;
+
 @end

@@ -78,9 +81,15 @@

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    CCThreadCell *cell = [[CCThreadCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
-    cell.thread = [_threads objectAtIndex:indexPath.row];
-//    CCThreadCell *cell = [[CCThreadCell alloc] initWithFrame:CGRectZero reuseIdentifier:nil];
+    CCSwipableCell *cell = [[CCSwipableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
+    cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    cell.contentView.backgroundColor = [UIColor whiteColor];
+    cell.textLabel.text = [NSString stringWithFormat:@"Cell %d", indexPath.row];
+    cell.swipeDirection = self.swipeDirection;
+    cell.delegate = self;
+
+
+//    CCThreadCell *cell = [[CCThreadCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
 //    cell.thread = [_threads objectAtIndex:indexPath.row];

     return cell;
@@ -174,6 +183,21 @@
 }

+
+#pragma mark - CCSwipableCell delegate
+
+- (void)cellDidReceiveSwipe:(CCSwipableCell *)cell
+{
+    [_currentlyActiveSlidingCell slideInContentView];
+    _currentlyActiveSlidingCell = cell;
+}
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
+{
+    [_currentlyActiveSlidingCell slideInContentView];
+    _currentlyActiveSlidingCell = nil;
+}
+
 @end