nikolaykasyanov
8/28/2013 - 11:00 AM

Rotation handling in reactive style. Kinda complex =\

Rotation handling in reactive style. Kinda complex =\

RACSignal *contentOffsetSignal = RACObserve(webView.scrollView, contentOffset);
RACSignal *contentSizeSignal = RACObserve(webView.scrollView, contentSize);

RACSignal *willRotateSignal = [self rac_signalForSelector:@selector(willRotateToInterfaceOrientation:duration:)];

// Sends @YES everytime orientation changes from portrait to landscape or vice-versa.
// will not send anything if changed from portrait to portrait upside down, for example.
RACSignal *orientationTypeChangedSignal = [[[willRotateSignal map:^(RACTuple *value) {
    return value.first;
}] combinePreviousWithStart:@(self.interfaceOrientation)
                     reduce:^(NSNumber *previous, NSNumber *current) {
                         UIInterfaceOrientation previousOrientation = (UIInterfaceOrientation) [previous integerValue];
                         UIInterfaceOrientation currentOrientation = (UIInterfaceOrientation) [current integerValue];

                         BOOL orientationTypeNotChanged =
                                (UIInterfaceOrientationIsPortrait(previousOrientation) && UIInterfaceOrientationIsPortrait(currentOrientation)) ||
                                (UIInterfaceOrientationIsLandscape(previousOrientation) && UIInterfaceOrientationIsLandscape(currentOrientation));

                         return @(!orientationTypeNotChanged);
                     }]
        filter:^BOOL(NSNumber *value) {
            return value.boolValue;
        }];

RACSignal *positionSignal = [[RACObserve(self, webView) sample:orientationTypeChangedSignal]
        map:^(UIWebView *webView) {
            CGPoint contentOffset = webView.scrollView.contentOffset;
            CGSize contentSize = webView.scrollView.contentSize;
            CGRect bounds = webView.scrollView.bounds;

            CGFloat maxXOffset = contentSize.width - CGRectGetWidth(bounds);

            return @( contentOffset.x / maxXOffset );
        }];

RACSignal *willAnimateRotationSignal = [self rac_signalForSelector:@selector(willAnimateRotationToInterfaceOrientation:duration:)];

RAC(self.webView.scrollView, contentOffset) = [[[positionSignal combineLatestWith:RACObserve(self, webView)]
        sample:willAnimateRotationSignal]
        map:^(RACTuple *tuple) {
            RACTupleUnpack(NSNumber *position, UIWebView *webView) = tuple;

            CGSize contentSize = webView.scrollView.contentSize;
            CGRect bounds = webView.scrollView.bounds;
            CGFloat viewPortWidth = CGRectGetWidth(bounds);
            CGFloat deltaX = viewPortWidth - 2 * ContentMargin;
            CGFloat idealXOffset = (contentSize.width - viewPortWidth) * position.floatValue;

            CGFloat newXOffset = (int)(idealXOffset / deltaX) * deltaX;

            return [NSValue valueWithCGPoint:CGPointMake(newXOffset, 0)];
        }];