2015-04-08 01:28:38 +03:00
//
// U I C o l l e c t i o n V i e w + R x . s w i f t
// R x C o c o a
//
// C r e a t e d b y K r u n o s l a v Z a h e r o n 4 / 2 / 1 5 .
2015-12-29 18:56:21 +03:00
// C o p y r i g h t © 2 0 1 5 K r u n o s l a v Z a h e r . A l l r i g h t s r e s e r v e d .
2015-04-08 01:28:38 +03:00
//
2015-09-30 15:02:41 +03:00
#if os ( iOS ) || os ( tvOS )
2015-04-08 01:28:38 +03:00
import Foundation
2015-08-01 16:13:26 +03:00
#if ! RX_NO_MODULE
2015-04-10 02:52:51 +03:00
import RxSwift
2015-08-01 16:13:26 +03:00
#endif
2015-05-17 20:07:24 +03:00
import UIKit
2015-04-08 01:28:38 +03:00
2015-08-29 22:20:44 +03:00
// I t e m s
2015-08-10 02:43:30 +03:00
2015-08-29 22:20:44 +03:00
extension UICollectionView {
2015-08-10 02:43:30 +03:00
2015-09-09 12:29:39 +03:00
/* *
Binds sequences of elements to collection view items .
- parameter source : Observable sequence of items .
- parameter cellFactory : Transform between sequence elements and view cells .
- returns : Disposable object that can be used to unbind .
*/
2015-08-29 22:20:44 +03:00
public func rx_itemsWithCellFactory < S : SequenceType , O : ObservableType where O . E = = S >
( source : O )
2016-02-04 00:19:31 +03:00
-> ( cellFactory : ( UICollectionView , Int , S . Generator . Element ) -> UICollectionViewCell )
2015-08-10 02:43:30 +03:00
-> Disposable {
2016-02-04 00:19:31 +03:00
return { cellFactory in
let dataSource = RxCollectionViewReactiveArrayDataSourceSequenceWrapper < S > ( cellFactory : cellFactory )
return self . rx_itemsWithDataSource ( dataSource ) ( source : source )
}
2015-08-10 02:43:30 +03:00
}
2015-09-09 12:29:39 +03:00
/* *
Binds sequences of elements to collection view items .
- parameter cellIdentifier : Identifier used to dequeue cells .
- parameter source : Observable sequence of items .
- parameter configureCell : Transform between sequence elements and view cells .
2015-12-21 03:19:08 +03:00
- parameter cellType : Type of table view cell .
2015-09-09 12:29:39 +03:00
- returns : Disposable object that can be used to unbind .
*/
2015-08-29 22:20:44 +03:00
public func rx_itemsWithCellIdentifier < S : SequenceType , Cell : UICollectionViewCell , O : ObservableType where O . E = = S >
2015-12-21 03:19:08 +03:00
( cellIdentifier : String , cellType : Cell . Type = Cell . self )
2016-02-04 00:19:31 +03:00
-> ( source : O )
-> ( configureCell : ( Int , S . Generator . Element , Cell ) -> Void )
2015-08-10 02:43:30 +03:00
-> Disposable {
2016-02-04 00:19:31 +03:00
return { source in
return { configureCell in
let dataSource = RxCollectionViewReactiveArrayDataSourceSequenceWrapper < S > { ( cv , i , item ) in
let indexPath = NSIndexPath ( forItem : i , inSection : 0 )
let cell = cv . dequeueReusableCellWithReuseIdentifier ( cellIdentifier , forIndexPath : indexPath ) as ! Cell
configureCell ( i , item , cell )
return cell
}
return self . rx_itemsWithDataSource ( dataSource ) ( source : source )
}
2015-08-10 02:43:30 +03:00
}
2015-08-29 22:20:44 +03:00
}
2015-09-09 12:29:39 +03:00
/* *
Binds sequences of elements to collection view items using a custom reactive data used to perform the transformation .
- parameter dataSource : Data source used to transform elements to view cells .
- parameter source : Observable sequence of items .
- returns : Disposable object that can be used to unbind .
*/
2015-08-29 22:20:44 +03:00
public func rx_itemsWithDataSource < DataSource : protocol < RxCollectionViewDataSourceType , UICollectionViewDataSource > , S : SequenceType , O : ObservableType where DataSource . Element = = S , O . E = = S >
( dataSource : DataSource )
2016-02-04 00:19:31 +03:00
-> ( source : O )
2015-08-29 22:20:44 +03:00
-> Disposable {
2016-02-04 00:19:31 +03:00
return { source in
return source . subscribeProxyDataSourceForObject ( self , dataSource : dataSource , retainDataSource : false ) { [ weak self ] ( _ : RxCollectionViewDataSourceProxy , event ) -> Void in
guard let collectionView = self else {
return
}
dataSource . collectionView ( collectionView , observedEvent : event )
2015-08-29 22:20:44 +03:00
}
}
2015-08-10 02:43:30 +03:00
}
}
2015-07-03 21:57:04 +03:00
extension UICollectionView {
2015-09-09 12:29:39 +03:00
/* *
Factory method that enables subclasses to implement their own ` rx_delegate ` .
2015-04-08 01:28:38 +03:00
2015-09-09 12:29:39 +03:00
- returns : Instance of delegate proxy that wraps ` delegate ` .
*/
2015-12-05 19:42:43 +03:00
public override func rx_createDelegateProxy ( ) -> RxScrollViewDelegateProxy {
2015-07-05 12:34:31 +03:00
return RxCollectionViewDelegateProxy ( parentObject : self )
2015-04-08 01:28:38 +03:00
}
2015-12-05 19:42:43 +03:00
/* *
Factory method that enables subclasses to implement their own ` rx_dataSource ` .
- returns : Instance of delegate proxy that wraps ` dataSource ` .
*/
public func rx_createDataSourceProxy ( ) -> RxCollectionViewDataSourceProxy {
return RxCollectionViewDataSourceProxy ( parentObject : self )
}
2015-06-29 01:54:05 +03:00
2015-09-09 12:29:39 +03:00
/* *
Reactive wrapper for ` dataSource ` .
2015-07-05 12:34:31 +03:00
2015-09-09 12:29:39 +03:00
For more information take a look at ` DelegateProxyType ` protocol documentation .
*/
2015-07-05 12:34:31 +03:00
public var rx_dataSource : DelegateProxy {
2016-03-07 20:31:00 +03:00
return proxyForObject ( RxCollectionViewDataSourceProxy . self , self )
2015-04-08 01:28:38 +03:00
}
2015-09-09 12:29:39 +03:00
/* *
Installs data source as forwarding delegate on ` rx_dataSource ` .
It enables using normal delegate mechanism with reactive delegate mechanism .
- parameter dataSource : Data source object .
- returns : Disposable object that can be used to unbind the data source .
*/
2015-07-05 19:40:06 +03:00
public func rx_setDataSource ( dataSource : UICollectionViewDataSource )
-> Disposable {
2015-12-05 19:42:43 +03:00
let proxy = proxyForObject ( RxCollectionViewDataSourceProxy . self , self )
2015-07-06 09:35:19 +03:00
return installDelegate ( proxy , delegate : dataSource , retainDelegate : false , onProxyForObject : self )
2015-07-05 19:40:06 +03:00
}
2015-09-09 12:29:39 +03:00
/* *
Reactive wrapper for ` delegate ` message ` collectionView : didSelectItemAtIndexPath : ` .
*/
2015-08-29 22:20:44 +03:00
public var rx_itemSelected : ControlEvent < NSIndexPath > {
2016-03-22 13:29:39 +03:00
let source = rx_delegate . observe ( #selector ( UICollectionViewDelegate . collectionView ( _ : didSelectItemAtIndexPath : ) ) )
2015-08-10 02:43:30 +03:00
. map { a in
2015-07-05 19:40:06 +03:00
return a [ 1 ] as ! NSIndexPath
}
2015-08-29 22:20:44 +03:00
2015-12-06 03:13:47 +03:00
return ControlEvent ( events : source )
2015-07-03 21:57:04 +03:00
}
2016-01-10 22:19:30 +03:00
/* *
Reactive wrapper for ` delegate ` message ` collectionView : didSelectItemAtIndexPath : ` .
*/
public var rx_itemDeselected : ControlEvent < NSIndexPath > {
2016-03-22 13:29:39 +03:00
let source = rx_delegate . observe ( #selector ( UICollectionViewDelegate . collectionView ( _ : didDeselectItemAtIndexPath : ) ) )
2016-01-10 22:19:30 +03:00
. map { a in
return a [ 1 ] as ! NSIndexPath
}
return ControlEvent ( events : source )
}
2015-09-09 12:29:39 +03:00
/* *
Reactive wrapper for ` delegate ` message ` collectionView : didSelectItemAtIndexPath : ` .
2016-01-10 22:19:30 +03:00
It can be only used when one of the ` rx_itemsWith * ` methods is used to bind observable sequence ,
or any other data source conforming to ` SectionedViewDataSourceType ` protocol .
2015-09-09 12:29:39 +03:00
2016-01-10 22:19:30 +03:00
` ` `
2015-11-28 13:58:58 +03:00
collectionView . rx_modelSelected ( MyModel . self )
. map { . . .
2016-01-10 22:19:30 +03:00
` ` `
2015-09-09 12:29:39 +03:00
*/
2015-11-28 13:58:58 +03:00
public func rx_modelSelected < T > ( modelType : T . Type ) -> ControlEvent < T > {
2015-10-19 01:52:11 +03:00
let source : Observable < T > = rx_itemSelected . flatMap { [ weak self ] indexPath -> Observable < T > in
guard let view = self else {
2015-12-21 23:34:48 +03:00
return Observable . empty ( )
2015-10-19 01:52:11 +03:00
}
2015-10-19 02:15:09 +03:00
2015-12-21 23:34:48 +03:00
return Observable . just ( try view . rx_modelAtIndexPath ( indexPath ) )
2015-10-18 20:23:53 +03:00
}
2015-10-16 22:20:13 +03:00
2015-12-06 03:13:47 +03:00
return ControlEvent ( events : source )
2015-10-16 22:20:13 +03:00
}
2016-01-10 22:19:30 +03:00
/* *
Reactive wrapper for ` delegate ` message ` collectionView : didSelectItemAtIndexPath : ` .
It can be only used when one of the ` rx_itemsWith * ` methods is used to bind observable sequence ,
or any other data source conforming to ` SectionedViewDataSourceType ` protocol .
` ` `
collectionView . rx_modelDeselected ( MyModel . self )
. map { . . .
` ` `
*/
public func rx_modelDeselected < T > ( modelType : T . Type ) -> ControlEvent < T > {
let source : Observable < T > = rx_itemDeselected . flatMap { [ weak self ] indexPath -> Observable < T > in
guard let view = self else {
return Observable . empty ( )
}
return Observable . just ( try view . rx_modelAtIndexPath ( indexPath ) )
}
return ControlEvent ( events : source )
}
2015-10-16 22:20:13 +03:00
2015-10-18 20:23:53 +03:00
/* *
Syncronous helper method for retrieving a model at indexPath through a reactive data source
*/
public func rx_modelAtIndexPath < T > ( indexPath : NSIndexPath ) throws -> T {
2016-01-10 22:19:30 +03:00
let dataSource : SectionedViewDataSourceType = castOrFatalError ( self . rx_dataSource . forwardToDelegate ( ) , message : " This method only works in case one of the `rx_itemsWith*` methods was used. " )
2015-08-29 22:20:44 +03:00
2016-01-10 22:19:30 +03:00
let element = try dataSource . modelAtIndexPath ( indexPath )
return element as ! T
2015-04-08 01:28:38 +03:00
}
2015-07-05 19:40:06 +03:00
}
2015-10-15 04:40:51 +03:00
#endif
#if os ( tvOS )
extension UICollectionView {
2015-10-16 22:20:13 +03:00
2015-10-15 04:40:51 +03:00
/* *
Reactive wrapper for ` delegate ` message ` collectionView : didUpdateFocusInContext : withAnimationCoordinator : ` .
*/
2015-10-18 20:23:53 +03:00
public var rx_didUpdateFocusInContextWithAnimationCoordinator : ControlEvent < ( context : UIFocusUpdateContext , animationCoordinator : UIFocusAnimationCoordinator ) > {
2015-10-16 22:20:13 +03:00
2016-03-22 14:12:15 +03:00
let source = rx_delegate . observe ( #selector ( UICollectionViewDelegate . collectionView ( _ : didUpdateFocusInContext : withAnimationCoordinator : ) ) )
2015-10-18 20:23:53 +03:00
. map { a -> ( context : UIFocusUpdateContext , animationCoordinator : UIFocusAnimationCoordinator ) in
2015-10-16 22:20:13 +03:00
let context = a [ 1 ] as ! UIFocusUpdateContext
let animationCoordinator = a [ 2 ] as ! UIFocusAnimationCoordinator
return ( context : context , animationCoordinator : animationCoordinator )
}
2015-12-06 03:13:47 +03:00
return ControlEvent ( events : source )
2015-10-16 22:20:13 +03:00
}
2015-10-15 04:40:51 +03:00
}
2015-09-30 15:02:41 +03:00
#endif