Skip to content

Commit

Permalink
add Paging
Browse files Browse the repository at this point in the history
  • Loading branch information
Malaar committed Apr 5, 2013
1 parent f9c27b1 commit 37a256a
Show file tree
Hide file tree
Showing 6 changed files with 434 additions and 0 deletions.
92 changes: 92 additions & 0 deletions MUKit/MUPaging/MUPaging.h
@@ -0,0 +1,92 @@
//
// CTPaging.h
// Apps4All
//
// Created by Malaar on 19.02.13.
// Copyright (c) 2013 Caiguda. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "MUPagingConfig.h"
#import "MUCompoundCell.h"
#import "MUGateway.h"
#import "MUFetchable.h"
#import "Reachability.h"
#import "MUTableDisposerModeled.h"

@protocol MUPagingDelegate;
@protocol MUPagingMoreCellProtocol;
@protocol MUPagingMoreCellDataProtocol;

@interface MUPaging : NSObject <MUFetchable>
{
Reachability* reachability;
MUCell<MUPagingMoreCellProtocol>* moreCell;
}

@property (nonatomic, readonly) MUPagingConfig* pagingConfig;
@property (nonatomic, readonly) UIViewController* controller;
@property (nonatomic, readonly) MUTableDisposerModeled* tableDisposer;

@property (nonatomic, weak) id<MUPagingDelegate> delegate;

@property (nonatomic, assign) BOOL reloading;
@property (nonatomic, assign) BOOL loadingMore;
@property (nonatomic, strong) NSDate* lastUpdate;

@property (nonatomic, readonly) MUGatewayTask* gatewayTask;
@property (nonatomic, readonly) NSUInteger pageOffset;
@property (nonatomic, readonly) NSMutableArray* models;
@property (nonatomic, readonly) NSMutableArray* compoundModels;

#pragma mark - Init/Dealloc
- (id)initWithConfig:(MUPagingConfig*)aPagingConfig
controller:(UIViewController*)aController
tableDisposer:(MUTableDisposerModeled*)aTableDisposer;

#pragma mark - Load/Reload data
- (void)reloadData;
- (void)loadMoreData;
- (MUGatewayTask*)fetchDataWithCallback:(MUGatewayCallback)aCallback;
- (NSArray*)didFetchData:(NSArray*)aData;
- (void)setupModels:(NSArray*)aModels;

#pragma mark - For MuTableDisposer
- (void)tableDisposer:(MUTableDisposerModeled*)aTableDisposer didCreateCellData:(MUCellData*)aCellData;
- (void)tableDisposer:(MUTableDisposerModeled*)aTableDisposer didCreateCell:(MUCell*)aCell;
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

#pragma mark - Notifications
- (void)reachabilityChangedNotification:(NSNotification*)aNotification;

@end


@protocol MUPagingDelegate <NSObject>

- (MUGatewayTask*)paging:(MUPaging*)aPaging fetchDataWithCallback:(MUGatewayCallback)aCallback;
- (MUCellData<MUPagingMoreCellDataProtocol>*)moreCellDataForPaging:(MUPaging*)aPaging;

@optional

- (BOOL)shouldFetchForPaging:(MUPaging*)aPaging;
- (void)willBeginFetchingForPaging:(MUPaging*)aPaging;
- (void)didCompleteFetchingForPaging:(MUPaging*)aPaging;

- (NSArray*)paging:(MUPaging*)aPaging didFetchedDataWithSuccess:(NSArray*)aData;
- (void)paging:(MUPaging*)aPaging didFetchedDataWithFailure:(MUGatewayResponse*)aResponse;

@end

@protocol MUPagingMoreCellProtocol <NSObject>

- (void)didBeginDataLoading;
- (void)didEndDataLoading;

@end

@protocol MUPagingMoreCellDataProtocol <NSObject>

- (void)addTarget:(id)aTarget action:(SEL)anAction;

@end
266 changes: 266 additions & 0 deletions MUKit/MUPaging/MUPaging.m
@@ -0,0 +1,266 @@
//
// CTPaging.m
// Apps4All
//
// Created by Malaar on 19.02.13.
// Copyright (c) 2013 Caiguda. All rights reserved.
//

#import "MUPaging.h"
#import "MUBOCompoundModel.h"

@interface MUPaging ()

@property (nonatomic) MUGatewayTask* gatewayTask;
@property (nonatomic, strong) MUCell<MUPagingMoreCellProtocol>* moreCell;

- (void)loadMoreDataPressed:(id*)aSender;

@end

@implementation MUPaging

@synthesize needFetch;
@synthesize pagingConfig;
@synthesize controller;
@synthesize tableDisposer;
@synthesize delegate;

@synthesize moreCell;
@synthesize reloading;
@synthesize loadingMore;
@synthesize lastUpdate;

@synthesize pageOffset;
@synthesize gatewayTask;
@synthesize models;
@synthesize compoundModels;

#pragma mark - Init/Dealloc

- (id)initWithConfig:(MUPagingConfig*)aPagingConfig
controller:(UIViewController*)aController
tableDisposer:(MUTableDisposerModeled*)aTableDisposer
{
self = [super init];
if(self)
{
pagingConfig = aPagingConfig;
controller = aController;
tableDisposer = aTableDisposer;

// defaults
needFetch = YES;
gatewayTask = nil;
pageOffset = 0;
reloading = YES;
loadingMore = NO;
lastUpdate = nil;

//
models = [NSMutableArray new];
compoundModels = [NSMutableArray new];

//
reachability = [Reachability reachabilityForInternetConnection];
[reachability startNotifier];

//
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reachabilityChangedNotification:)
name:kReachabilityChangedNotification object:nil];

if(pagingConfig.useCompoundCells)
{
[tableDisposer registerCellData:[MUCompoundCellData class] forModel:[MUBOCompoundModel class]];
}
}
return self;
}

- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Load/Reload data

- (void)reloadData
{
[gatewayTask cancel];
gatewayTask = nil;
pageOffset = 0;
[models removeAllObjects];
[compoundModels removeAllObjects];
reloading = YES;
self.needFetch = YES;
[self fetchData];
}

- (void)loadMoreData
{
pageOffset += pagingConfig.pageSize;
loadingMore = YES;
self.needFetch = YES;
[self fetchData];
}

- (MUGatewayTask*)fetchDataWithCallback:(MUGatewayCallback)aCallback
{
return [delegate paging:self fetchDataWithCallback:aCallback];
}

- (NSArray*)didFetchData:(NSArray*)aData
{
return aData; // override if you need
}

- (void)setupModels:(NSArray*)aModels
{
[tableDisposer removeAllSections];
MUSectionReadonly* section = [MUSectionReadonly section];
[tableDisposer addSection:section];

[models addObjectsFromArray:aModels];
tableDisposer.tableView.hidden = models.count == 0;

if(pagingConfig.useCompoundCells)
{
NSArray* compoundModelsNew = [MUBOCompoundModel compoundModelsFromModels:aModels
groupByCount:pagingConfig.compoundCellsGroupByCount];
[compoundModels addObjectsFromArray:compoundModelsNew];
[tableDisposer setupModels:compoundModels forSection:section];
}
else
{
[tableDisposer setupModels:models forSection:section];
}

if(aModels.count == pagingConfig.pageSize)
{
MUCellData<MUPagingMoreCellDataProtocol>* moreCellData = [delegate moreCellDataForPaging:self];
[moreCellData addTarget:self action:@selector(loadMoreDataPressed:)];
[section addCellData:moreCellData];
}
else
{
moreCell = nil;
}
[tableDisposer reloadData];
}

#pragma mark - MUFetchable
- (void)fetchData
{
if(!self.needFetch)
return;

if([delegate respondsToSelector:@selector(shouldFetchForPaging:)])
{
if(![delegate shouldFetchForPaging:self])
return;
}

self.needFetch = NO;

if(loadingMore)
[moreCell didBeginDataLoading];

if([delegate respondsToSelector:@selector(willBeginFetchingForPaging:)])
[delegate willBeginFetchingForPaging:self];

[gatewayTask cancel];
__weak MUPaging* __self = self;
gatewayTask = [self fetchDataWithCallback:^(MUGatewayResponse *aResponse, BOOL aSuccess)
{
__self.gatewayTask = nil;
__self.needFetch = aResponse.boArray.count == 0;

if(__self.reloading)
{
if(aSuccess)
__self.lastUpdate = [NSDate date];
}

if([delegate respondsToSelector:@selector(didCompleteFetchingForPaging:)])
[__self.delegate didCompleteFetchingForPaging:__self];

if(aSuccess)
{
NSArray* fetchedModels = [self didFetchData:aResponse.boArray];

if([__self.delegate respondsToSelector:@selector(paging:didFetchedDataWithSuccess:)])
fetchedModels = [__self.delegate paging:self didFetchedDataWithSuccess:fetchedModels];

[__self setupModels:fetchedModels];
}
else
{
[__self.moreCell didEndDataLoading];

if([__self.delegate respondsToSelector:@selector(paging:didFetchedDataWithFailure:)])
[__self.delegate paging:__self didFetchedDataWithFailure:aResponse];
}

__self.reloading = NO;
__self.loadingMore = NO;

}];
}

#pragma mark - For MuTableDisposer

- (void)tableDisposer:(MUTableDisposerModeled*)aTableDisposer didCreateCellData:(MUCellData*)aCellData
{
if(aTableDisposer != tableDisposer)
return;

if(pagingConfig.useCompoundCells)
{
if([aCellData isKindOfClass:[MUCompoundCellData class]])
{
[(MUCompoundCellData*)aCellData setTableDisposer:tableDisposer];
}
}
}

- (void)tableDisposer:(MUTableDisposerModeled*)aTableDisposer didCreateCell:(MUCell*)aCell
{
if(aTableDisposer != tableDisposer)
return;

if([aCell.cellData conformsToProtocol:@protocol(MUPagingMoreCellDataProtocol)])
{
moreCell = (MUCell<MUPagingMoreCellProtocol>*)aCell;
}
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
{
if(tableDisposer.tableView != tableView)
return;

if(pagingConfig.loadMoreDataType == MULoadMoreDataTypeAuto)
{
if(cell == moreCell)
{
[self loadMoreData];
}
}
}

#pragma mark - Actions

- (void)loadMoreDataPressed:(id*)aSender
{
[self loadMoreData];
}

#pragma mark - Notifications
- (void)reachabilityChangedNotification:(NSNotification*)aNotification
{
if([reachability isReachable])
[self reloadData];
}

@end
27 changes: 27 additions & 0 deletions MUKit/MUPaging/MUPagingConfig.h
@@ -0,0 +1,27 @@
//
// CTPagingConfig.h
// Apps4All
//
// Created by Malaar on 19.02.13.
// Copyright (c) 2013 Caiguda. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef enum _MULoadMoreDataType
{
MULoadMoreDataTypeAuto,
MULoadMoreDataTypeManual

} MULoadMoreDataType;

@interface MUPagingConfig : NSObject

@property (nonatomic, assign) NSUInteger pageSize;
//@property (nonatomic, assign) BOOL enablePullToRefresh;
//@property (nonatomic, assign) BOOL enablePaging;
@property (nonatomic, assign) MULoadMoreDataType loadMoreDataType;
@property (nonatomic, assign) BOOL useCompoundCells;
@property (nonatomic, assign) NSUInteger compoundCellsGroupByCount;

@end

0 comments on commit 37a256a

Please sign in to comment.