import { KeyedTemplate , Length , View } from "ui/core/view" ; import { GridLayout } from "ui/layouts/grid-layout" ; import * as utils from "utils/utils" ; import { GridViewBase , colWidthProperty , itemTemplatesProperty , orientationProperty , paddingBottomProperty , paddingLeftProperty , paddingRightProperty , paddingTopProperty , rowHeightProperty , } from "./grid-view-common" ; import { GridItemEventData , Orientation , ScrollEventData } from "." ; export * from "./grid-view-common" ; const DUMMY = "DUMMY" ; export class GridView extends GridViewBase { public nativeView : android . support . v7 . widget . RecyclerView ; public _realizedItems = new Map < android . view . View , View > ( ) ; public createNativeView ( ) { initGridViewRecyclerView ( ) ; const recyclerView = new GridViewRecyclerView ( this . _context , new WeakRef ( this ) ) ; initGridViewAdapter ( ) ; const adapter = new GridViewAdapter ( new WeakRef ( this ) ) ; adapter . setHasStableIds ( true ) ; recyclerView . setAdapter ( adapter ) ; ( recyclerView as any ) . adapter = adapter ; const orientation = this . _getLayoutManagarOrientation ( ) ; const layoutManager = new android . support . v7 . widget . GridLayoutManager ( this . _context , 1 ) ; recyclerView . setLayoutManager ( layoutManager ) ; layoutManager . setOrientation ( orientation ) ; ( recyclerView as any ) . layoutManager = layoutManager ; initGridViewScrollListener ( ) ; const scrollListener = new GridViewScrollListener ( new WeakRef ( this ) ) ; recyclerView . addOnScrollListener ( scrollListener ) ; ( recyclerView as any ) . scrollListener = scrollListener ; return recyclerView ; } public initNativeView ( ) { super . initNativeView ( ) ; const nativeView = this . nativeView as any ; nativeView . adapter . owner = new WeakRef ( this ) ; nativeView . scrollListener . owner = new WeakRef ( this ) ; nativeView . owner = new WeakRef ( this ) ; colWidthProperty . coerce ( this ) ; rowHeightProperty . coerce ( this ) ; } public disposeNativeView ( ) { this . eachChildView ( ( view ) => { view . parent . _removeView ( view ) ; return true ; } ) ; this . _realizedItems . clear ( ) ; const nativeView = this . nativeView as any ; this . nativeView . removeOnScrollListener ( nativeView . scrollListener ) ; nativeView . scrollListener = null ; nativeView . adapter = null ; nativeView . layoutManager = null ; super . disposeNativeView ( ) ; } get android ( ) : android . support . v7 . widget . RecyclerView { return this . nativeView ; } get _childrenCount ( ) : number { return this . _realizedItems . size ; } public [ paddingTopProperty . getDefault ] ( ) { return ( ( this . nativeView as any ) as android . view . View ) . getPaddingTop ( ) ; } public [ paddingTopProperty . setNative ] ( value ) { this . _setPadding ( { top : this . effectivePaddingTop } ) ; } public [ paddingRightProperty . getDefault ] ( ) { return ( ( this . nativeView as any ) as android . view . View ) . getPaddingRight ( ) ; } public [ paddingRightProperty . setNative ] ( value ) { this . _setPadding ( { right : this . effectivePaddingRight } ) ; } public [ paddingBottomProperty . getDefault ] ( ) { return ( ( this . nativeView as any ) as android . view . View ) . getPaddingBottom ( ) ; } public [ paddingBottomProperty . setNative ] ( value ) { this . _setPadding ( { bottom : this . effectivePaddingBottom } ) ; } public [ paddingLeftProperty . getDefault ] ( ) { return ( ( this . nativeView as any ) as android . view . View ) . getPaddingLeft ( ) ; } public [ paddingLeftProperty . setNative ] ( value ) { this . _setPadding ( { left : this . effectivePaddingLeft } ) ; } public [ orientationProperty . getDefault ] ( ) { const layoutManager = this . nativeView . getLayoutManager ( ) as android . support . v7 . widget . GridLayoutManager ; if ( layoutManager . getOrientation ( ) === android . support . v7 . widget . LinearLayoutManager . HORIZONTAL ) { return "horizontal" ; } return "vertical" ; } public [ orientationProperty . setNative ] ( value ) { const layoutManager = this . nativeView . getLayoutManager ( ) as android . support . v7 . widget . GridLayoutManager ; if ( value === "horizontal" ) { layoutManager . setOrientation ( android . support . v7 . widget . LinearLayoutManager . HORIZONTAL ) ; } else { layoutManager . setOrientation ( android . support . v7 . widget . LinearLayoutManager . VERTICAL ) ; } } public [ itemTemplatesProperty . getDefault ] ( ) { return null ; } public [ itemTemplatesProperty . setNative ] ( value ) { this . _itemTemplatesInternal = new Array < KeyedTemplate > ( this . _defaultTemplate ) ; if ( value ) { this . _itemTemplatesInternal = this . _itemTemplatesInternal . concat ( value ) ; } this . nativeViewProtected . setAdapter ( new GridViewAdapter ( new WeakRef ( this ) ) ) ; this . refresh ( ) ; } public eachChildView ( callback ) { this . _realizedItems . forEach ( ( view , key ) => { callback ( view ) ; } ) ; } public onLayout ( left , top , right , bottom ) { super . onLayout ( left , top , right , bottom ) ; this . refresh ( ) ; } public refresh ( ) { if ( ! this . nativeView || ! this . nativeView . getAdapter ( ) ) { return ; } const layoutManager = this . nativeView . getLayoutManager ( ) as android . support . v7 . widget . GridLayoutManager ; let spanCount ; if ( this . orientation === "horizontal" ) { spanCount = Math . max ( Math . floor ( this . _innerHeight / this . _effectiveRowHeight ) , 1 ) || 1 ; } else { spanCount = Math . max ( Math . floor ( this . _innerWidth / this . _effectiveColWidth ) , 1 ) || 1 ; } layoutManager . setSpanCount ( spanCount ) ; this . nativeView . getAdapter ( ) . notifyDataSetChanged ( ) ; } public scrollToIndex ( index , animated = true ) { if ( animated ) { this . nativeView . smoothScrollToPosition ( index ) ; } else { this . nativeView . scrollToPosition ( index ) ; } } private _setPadding ( newPadding ) { const nativeView = this . nativeView as any ; const padding = { top : nativeView . getPaddingTop ( ) , right : nativeView . getPaddingRight ( ) , bottom : nativeView . getPaddingBottom ( ) , left : nativeView . getPaddingLeft ( ) } ; const newValue = Object . assign ( padding , newPadding ) ; nativeView . setPadding ( newValue . left , newValue . top , newValue . right , newValue . bottom ) ; } private _getLayoutManagarOrientation ( ) { let orientation = android . support . v7 . widget . LinearLayoutManager . VERTICAL ; if ( this . orientation === "horizontal" ) { orientation = android . support . v7 . widget . LinearLayoutManager . HORIZONTAL ; } return orientation ; } } interface GridViewScrollListener extends android . support . v7 . widget . RecyclerView . OnScrollListener { new ( owner ) : GridViewScrollListener ; } let GridViewScrollListener ; function initGridViewScrollListener ( ) { if ( GridViewScrollListener ) { return ; } class GridViewScrollListenerImpl extends android . support . v7 . widget . RecyclerView . OnScrollListener { constructor ( private owner ) { super ( ) ; return global . __native ( this ) ; } public onScrolled ( view , dx , dy ) { const owner = this . owner . get ( ) ; if ( ! owner ) { return ; } owner . notify < ScrollEventData > ( { eventName : GridViewBase . scrollEvent , object : owner , scrollX : dx , scrollY : dy , } ) ; const lastVisibleItemPos = ( view . getLayoutManager ( ) as android . support . v7 . widget . GridLayoutManager ) . findLastCompletelyVisibleItemPosition ( ) ; if ( owner && owner . items ) { const itemCount = owner . items . length - 1 ; if ( lastVisibleItemPos === itemCount ) { owner . notify ( { eventName : GridViewBase . loadMoreItemsEvent , object : owner } ) ; } } } public onScrollStateChanged ( view , newState ) { } } GridViewScrollListener = GridViewScrollListenerImpl as any ; } interface GridViewAdapter extends android . support . v7 . widget . RecyclerView . Adapter { new ( owner ) : GridViewAdapter ; } let GridViewAdapter ; function initGridViewAdapter ( ) { if ( GridViewAdapter ) { return ; } @ Interfaces ( [ android . view . View . OnClickListener ] ) class GridViewCellHolder extends android . support . v7 . widget . RecyclerView . ViewHolder implements android . view . View . OnClickListener { constructor ( private owner , private gridView ) { super ( owner . get ( ) . android ) ; const nativeThis = global . __native ( this ) ; const nativeView = owner . get ( ) . android as android . view . View ; nativeView . setOnClickListener ( nativeThis ) ; return nativeThis ; } get view ( ) : View { return this . owner ? this . owner . get ( ) : null ; } public onClick ( v ) { const gridView = this . gridView . get ( ) ; gridView . notify < GridItemEventData > ( { eventName : GridViewBase . itemTapEvent , object : gridView , index : this . getAdapterPosition ( ) , view : this . view , android : v , ios : undefined , } ) ; } } class GridViewAdapterImpl extends android . support . v7 . widget . RecyclerView . Adapter { constructor ( private owner ) { super ( ) ; return global . __native ( this ) ; } public getItemCount ( ) { const owner = this . owner . get ( ) ; return owner . items ? owner . items . length : 0 ; } public getItem ( i ) { const owner = this . owner . get ( ) ; if ( owner && owner . items && i < owner . items . length ) { return owner . _getDataItem ( i ) ; } return null ; } public getItemId ( i ) { const owner = this . owner . get ( ) ; const item = this . getItem ( i ) ; let id = i ; if ( this . owner && item && owner . items ) { id = owner . itemIdGenerator ( item , i , owner . items ) ; } return long ( id ) ; } public getItemViewType ( index ) { const owner = this . owner . get ( ) ; const template = owner . _getItemTemplate ( index ) ; const itemViewType = owner . _itemTemplatesInternal . indexOf ( template ) ; return itemViewType ; } public onCreateViewHolder ( parent , viewType ) { const owner = this . owner . get ( ) ; const template = owner . _itemTemplatesInternal [ viewType ] ; let view = template . createView ( ) ; if ( ! view ) { view = new GridLayout ( ) ; view [ DUMMY ] = true ; } owner . _addView ( view ) ; owner . _realizedItems . set ( view . android , view ) ; return new GridViewCellHolder ( new WeakRef ( view ) , new WeakRef ( owner ) ) ; } public onBindViewHolder ( vh , index ) { const owner = this . owner . get ( ) ; const args = { eventName : GridViewBase . itemLoadingEvent , object : owner , index , view : vh . view [ DUMMY ] ? null : vh . view , android : vh , ios : undefined , } ; owner . notify ( args ) ; if ( vh . view [ DUMMY ] ) { ( vh . view as GridLayout ) . addChild ( args . view ) ; vh . view [ DUMMY ] = undefined ; } if ( owner . orientation === "horizontal" ) { vh . view . width = utils . layout . toDeviceIndependentPixels ( owner . _effectiveColWidth ) ; } else { vh . view . height = utils . layout . toDeviceIndependentPixels ( owner . _effectiveRowHeight ) ; } owner . _prepareItem ( vh . view , index ) ; } } GridViewAdapter = GridViewAdapterImpl as any ; } interface GridViewRecyclerView extends android . support . v7 . widget . RecyclerView { new ( context , owner ) : GridViewRecyclerView ; } let GridViewRecyclerView ; function initGridViewRecyclerView ( ) { if ( GridViewRecyclerView ) { return ; } class GridViewRecyclerViewImpl extends android . support . v7 . widget . RecyclerView { constructor ( context , private owner ) { super ( context ) ; return global . __native ( this ) ; } public onLayout ( changed , l , t , r , b ) { if ( changed ) { const owner = this . owner . get ( ) ; owner . onLayout ( l , t , r , b ) ; } super . onLayout ( changed , l , t , r , b ) ; } } GridViewRecyclerView = GridViewRecyclerViewImpl as any ; }