2  *   ownCloud Android client application 
   4  *   Copyright (C) 2012 Bartek Przybylski 
   5  *   Copyright (C) 2012-2015 ownCloud Inc. 
   7  *   This program is free software: you can redistribute it and/or modify 
   8  *   it under the terms of the GNU General Public License version 2, 
   9  *   as published by the Free Software Foundation. 
  11  *   This program is distributed in the hope that it will be useful, 
  12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  14  *   GNU General Public License for more details. 
  16  *   You should have received a copy of the GNU General Public License 
  17  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  21 package com
.owncloud
.android
.ui
.fragment
; 
  23 import java
.util
.ArrayList
; 
  25 import android
.os
.Build
; 
  26 import android
.os
.Bundle
; 
  27 import android
.support
.v4
.app
.Fragment
; 
  28 import android
.support
.v4
.widget
.SwipeRefreshLayout
; 
  29 import android
.view
.LayoutInflater
; 
  30 import android
.view
.View
; 
  31 import android
.view
.ViewGroup
; 
  32 import android
.widget
.AbsListView
; 
  33 import android
.widget
.AdapterView
; 
  34 import android
.widget
.AdapterView
.OnItemClickListener
; 
  35 import android
.widget
.GridView
; 
  36 import android
.widget
.ListAdapter
; 
  37 import android
.widget
.ListView
; 
  38 import android
.widget
.TextView
; 
  40 import com
.owncloud
.android
.R
; 
  41 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
; 
  42 import com
.owncloud
.android
.ui
.ExtendedListView
; 
  43 import com
.owncloud
.android
.ui
.activity
.OnEnforceableRefreshListener
; 
  44 import com
.owncloud
.android
.ui
.adapter
.FileListListAdapter
; 
  46 import third_parties
.in.srain
.cube
.GridViewWithHeaderAndFooter
; 
  49  * TODO extending SherlockListFragment instead of SherlockFragment 
  51 public class ExtendedListFragment 
extends Fragment
 
  52         implements OnItemClickListener
, OnEnforceableRefreshListener 
{ 
  54     private static final String TAG 
= ExtendedListFragment
.class.getSimpleName(); 
  56     private static final String KEY_SAVED_LIST_POSITION 
= "SAVED_LIST_POSITION"; 
  57     private static final String KEY_INDEXES 
= "INDEXES"; 
  58     private static final String KEY_FIRST_POSITIONS
= "FIRST_POSITIONS"; 
  59     private static final String KEY_TOPS 
= "TOPS"; 
  60     private static final String KEY_HEIGHT_CELL 
= "HEIGHT_CELL"; 
  61     private static final String KEY_EMPTY_LIST_MESSAGE 
= "EMPTY_LIST_MESSAGE"; 
  63     private SwipeRefreshLayout mRefreshListLayout
; 
  64     private SwipeRefreshLayout mRefreshGridLayout
; 
  65     private SwipeRefreshLayout mRefreshEmptyLayout
; 
  66     private TextView mEmptyListMessage
; 
  68     // Save the state of the scroll in browsing 
  69     private ArrayList
<Integer
> mIndexes
; 
  70     private ArrayList
<Integer
> mFirstPositions
; 
  71     private ArrayList
<Integer
> mTops
; 
  72     private int mHeightCell 
= 0; 
  74     private SwipeRefreshLayout
.OnRefreshListener mOnRefreshListener 
= null
; 
  76     protected AbsListView mCurrentListView
; 
  77     private ExtendedListView mListView
; 
  78     private View mListFooterView
; 
  79     private GridViewWithHeaderAndFooter mGridView
; 
  80     private View mGridFooterView
; 
  82     private ListAdapter mAdapter
; 
  84     protected void setListAdapter(ListAdapter listAdapter
) { 
  85         mAdapter 
= listAdapter
; 
  86         if (android
.os
.Build
.VERSION
.SDK_INT 
>= Build
.VERSION_CODES
.HONEYCOMB
) { 
  87             mCurrentListView
.setAdapter(listAdapter
); 
  89             ((ListView
)mCurrentListView
).setAdapter(listAdapter
); 
  92         mCurrentListView
.invalidate(); 
  95     protected AbsListView 
getListView() { 
  96         return mCurrentListView
; 
 100     protected void switchToGridView() { 
 101         if ((mCurrentListView 
== mListView
)) { 
 103             mListView
.setAdapter(null
); 
 104             mRefreshListLayout
.setVisibility(View
.GONE
); 
 106             if (mAdapter 
instanceof FileListListAdapter
) { 
 107                 ((FileListListAdapter
) mAdapter
).setGridMode(true
); 
 109             mGridView
.setAdapter(mAdapter
); 
 110             mRefreshGridLayout
.setVisibility(View
.VISIBLE
); 
 112             mCurrentListView 
= mGridView
; 
 116     protected void switchToListView() { 
 117         if (mCurrentListView 
== mGridView
) { 
 118             mGridView
.setAdapter(null
); 
 119             mRefreshGridLayout
.setVisibility(View
.GONE
); 
 121             if (mAdapter 
instanceof FileListListAdapter
) { 
 122                 ((FileListListAdapter
) mAdapter
).setGridMode(false
); 
 124             mListView
.setAdapter(mAdapter
); 
 125             mRefreshListLayout
.setVisibility(View
.VISIBLE
); 
 127             mCurrentListView 
= mListView
; 
 133     public View 
onCreateView(LayoutInflater inflater
, ViewGroup container
, 
 134                              Bundle savedInstanceState
) { 
 135         Log_OC
.d(TAG
, "onCreateView"); 
 137         View v 
= inflater
.inflate(R
.layout
.list_fragment
, null
); 
 139         mListView 
= (ExtendedListView
)(v
.findViewById(R
.id
.list_root
)); 
 140         mListView
.setOnItemClickListener(this); 
 141         mListFooterView 
= inflater
.inflate(R
.layout
.list_footer
, null
, false
); 
 143         mGridView 
= (GridViewWithHeaderAndFooter
) (v
.findViewById(R
.id
.grid_root
)); 
 144         mGridView
.setNumColumns(GridView
.AUTO_FIT
); 
 145         mGridView
.setOnItemClickListener(this); 
 146         mGridFooterView 
= inflater
.inflate(R
.layout
.list_footer
, null
, false
); 
 148         if (savedInstanceState 
!= null
) { 
 149             int referencePosition 
= savedInstanceState
.getInt(KEY_SAVED_LIST_POSITION
); 
 150             if (mCurrentListView 
== mListView
) { 
 151                 Log_OC
.v(TAG
, "Setting and centering around list position " + referencePosition
); 
 152                 mListView
.setAndCenterSelection(referencePosition
); 
 154                 Log_OC
.v(TAG
, "Setting grid position " + referencePosition
); 
 155                 mGridView
.setSelection(referencePosition
); 
 159         // Pull-down to refresh layout 
 160         mRefreshListLayout 
= (SwipeRefreshLayout
) v
.findViewById(R
.id
.swipe_containing_list
); 
 161         mRefreshGridLayout 
= (SwipeRefreshLayout
) v
.findViewById(R
.id
.swipe_containing_grid
); 
 162         mRefreshEmptyLayout 
= (SwipeRefreshLayout
) v
.findViewById(R
.id
.swipe_containing_empty
); 
 163         mEmptyListMessage 
= (TextView
) v
.findViewById(R
.id
.empty_list_view
); 
 165         onCreateSwipeToRefresh(mRefreshListLayout
); 
 166         onCreateSwipeToRefresh(mRefreshGridLayout
); 
 167         onCreateSwipeToRefresh(mRefreshEmptyLayout
); 
 169         mListView
.setEmptyView(mRefreshEmptyLayout
); 
 170         mGridView
.setEmptyView(mRefreshEmptyLayout
); 
 172         mCurrentListView 
= mListView
;   // list as default 
 181     public void onActivityCreated(Bundle savedInstanceState
) { 
 182         super.onActivityCreated(savedInstanceState
); 
 184         if (savedInstanceState 
!= null
) { 
 185             mIndexes 
= savedInstanceState
.getIntegerArrayList(KEY_INDEXES
); 
 186             mFirstPositions 
= savedInstanceState
.getIntegerArrayList(KEY_FIRST_POSITIONS
); 
 187             mTops 
= savedInstanceState
.getIntegerArrayList(KEY_TOPS
); 
 188             mHeightCell 
= savedInstanceState
.getInt(KEY_HEIGHT_CELL
); 
 189             setMessageForEmptyList(savedInstanceState
.getString(KEY_EMPTY_LIST_MESSAGE
)); 
 192             mIndexes 
= new ArrayList
<Integer
>(); 
 193             mFirstPositions 
= new ArrayList
<Integer
>(); 
 194             mTops 
= new ArrayList
<Integer
>(); 
 201     public void onSaveInstanceState(Bundle savedInstanceState
) { 
 202         super.onSaveInstanceState(savedInstanceState
); 
 203         Log_OC
.d(TAG
, "onSaveInstanceState()"); 
 204         savedInstanceState
.putInt(KEY_SAVED_LIST_POSITION
, getReferencePosition()); 
 205         savedInstanceState
.putIntegerArrayList(KEY_INDEXES
, mIndexes
); 
 206         savedInstanceState
.putIntegerArrayList(KEY_FIRST_POSITIONS
, mFirstPositions
); 
 207         savedInstanceState
.putIntegerArrayList(KEY_TOPS
, mTops
); 
 208         savedInstanceState
.putInt(KEY_HEIGHT_CELL
, mHeightCell
); 
 209         savedInstanceState
.putString(KEY_EMPTY_LIST_MESSAGE
, getEmptyViewText()); 
 213      * Calculates the position of the item that will be used as a reference to 
 214      * reposition the visible items in the list when the device is turned to 
 217      * The current policy is take as a reference the visible item in the center 
 220      * @return The position in the list of the visible item in the center of the 
 223     protected int getReferencePosition() { 
 224         if (mCurrentListView 
!= null
) { 
 225             return (mCurrentListView
.getFirstVisiblePosition() + 
 226                     mCurrentListView
.getLastVisiblePosition()) / 2; 
 234      * Restore index and position 
 236     protected void restoreIndexAndTopPosition() { 
 237         if (mIndexes
.size() > 0) {   
 238             // needs to be checked; not every browse-up had a browse-down before  
 240             int index 
= mIndexes
.remove(mIndexes
.size() - 1); 
 241             final int firstPosition 
= mFirstPositions
.remove(mFirstPositions
.size() -1); 
 242             int top 
= mTops
.remove(mTops
.size() - 1); 
 244             Log_OC
.v(TAG
, "Setting selection to position: " + firstPosition 
+ "; top: " 
 245                     + top 
+ "; index: " + index
); 
 247             if (mCurrentListView 
== mListView
) { 
 248                 if (mHeightCell
*index 
<= mListView
.getHeight()) { 
 249                     mListView
.setSelectionFromTop(firstPosition
, top
); 
 251                     mListView
.setSelectionFromTop(index
, 0); 
 255                 if (mHeightCell
*index 
<= mGridView
.getHeight()) { 
 256                     mGridView
.setSelection(firstPosition
); 
 257                     //mGridView.smoothScrollToPosition(firstPosition); 
 259                     mGridView
.setSelection(index
); 
 260                     //mGridView.smoothScrollToPosition(index); 
 268      * Save index and top position 
 270     protected void saveIndexAndTopPosition(int index
) { 
 274         int firstPosition 
= mCurrentListView
.getFirstVisiblePosition(); 
 275         mFirstPositions
.add(firstPosition
); 
 277         View view 
= mCurrentListView
.getChildAt(0); 
 278         int top 
= (view 
== null
) ? 
0 : view
.getTop() ; 
 282         // Save the height of a cell 
 283         mHeightCell 
= (view 
== null 
|| mHeightCell 
!= 0) ? mHeightCell 
: view
.getHeight(); 
 288     public void onItemClick (AdapterView
<?
> parent
, View view
, int position
, long id
) { 
 293     public void onRefresh() { 
 294         mRefreshListLayout
.setRefreshing(false
); 
 295         mRefreshGridLayout
.setRefreshing(false
); 
 296         mRefreshEmptyLayout
.setRefreshing(false
); 
 298         if (mOnRefreshListener 
!= null
) { 
 299             mOnRefreshListener
.onRefresh(); 
 302     public void setOnRefreshListener(OnEnforceableRefreshListener listener
) { 
 303         mOnRefreshListener 
= listener
; 
 308      * Disables swipe gesture. 
 310      * Sets the 'enabled' state of the refresh layouts contained in the fragment. 
 312      * When 'false' is set, prevents user gestures but keeps the option to refresh programatically, 
 314      * @param   enabled     Desired state for capturing swipe gesture. 
 316     public void setSwipeEnabled(boolean enabled
) { 
 317         mRefreshListLayout
.setEnabled(enabled
); 
 318         mRefreshGridLayout
.setEnabled(enabled
); 
 319         mRefreshEmptyLayout
.setEnabled(enabled
); 
 323      * Set message for empty list view 
 325     public void setMessageForEmptyList(String message
) { 
 326         if (mEmptyListMessage 
!= null
) { 
 327             mEmptyListMessage
.setText(message
); 
 332      * Get the text of EmptyListMessage TextView 
 336     public String 
getEmptyViewText() { 
 337         return (mEmptyListMessage 
!= null
) ? mEmptyListMessage
.getText().toString() : ""; 
 340     private void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout
) { 
 341         // Colors in animations 
 342         refreshLayout
.setColorSchemeResources(R
.color
.color_accent
, R
.color
.primary
, 
 343                 R
.color
.primary_dark
); 
 345         refreshLayout
.setOnRefreshListener(this); 
 349     public void onRefresh(boolean ignoreETag
) { 
 350         mRefreshListLayout
.setRefreshing(false
); 
 351         mRefreshGridLayout
.setRefreshing(false
); 
 352         mRefreshEmptyLayout
.setRefreshing(false
); 
 354         if (mOnRefreshListener 
!= null
) { 
 355             mOnRefreshListener
.onRefresh(); 
 359     protected void setChoiceMode(int choiceMode
) { 
 360         if (android
.os
.Build
.VERSION
.SDK_INT 
>= Build
.VERSION_CODES
.HONEYCOMB
) { 
 361             mListView
.setChoiceMode(choiceMode
); 
 362             mGridView
.setChoiceMode(choiceMode
); 
 364             ((ListView
)mListView
).setChoiceMode(choiceMode
); 
 368     protected void registerForContextMenu() { 
 369         registerForContextMenu(mListView
); 
 370         registerForContextMenu(mGridView
); 
 371         mListView
.setOnCreateContextMenuListener(this); 
 372         mGridView
.setOnCreateContextMenuListener(this); 
 377      * To be called before setAdapter, or GridViewWithHeaderAndFooter will throw an exception 
 381     protected void setFooterEnabled(boolean enabled
) { 
 383             if (mGridView
.getFooterViewCount() == 0) { 
 384                 if (mGridFooterView
.getParent() != null 
) { 
 385                     ((ViewGroup
) mGridFooterView
.getParent()).removeView(mGridFooterView
); 
 387                 mGridView
.addFooterView(mGridFooterView
, null
, false
); 
 389             mGridFooterView
.invalidate(); 
 391             if (mListView
.getFooterViewsCount() == 0) { 
 392                 if (mListFooterView
.getParent() != null 
) { 
 393                     ((ViewGroup
) mListFooterView
.getParent()).removeView(mListFooterView
); 
 395                 mListView
.addFooterView(mListFooterView
, null
, false
); 
 397             mListFooterView
.invalidate(); 
 400             mGridView
.removeFooterView(mGridFooterView
); 
 401             mListView
.removeFooterView(mListFooterView
); 
 409     protected void setFooterText(String text
) { 
 410         if (text 
!= null 
&& text
.length() > 0) { 
 411             ((TextView
)mListFooterView
.findViewById(R
.id
.footerText
)).setText(text
); 
 412             ((TextView
)mGridFooterView
.findViewById(R
.id
.footerText
)).setText(text
); 
 413             setFooterEnabled(true
); 
 416             setFooterEnabled(false
);