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
.ActionMode
; 
  30 import android
.view
.LayoutInflater
; 
  31 import android
.view
.Menu
; 
  32 import android
.view
.MenuItem
; 
  33 import android
.view
.View
; 
  34 import android
.view
.ViewGroup
; 
  35 import android
.widget
.AbsListView
; 
  36 import android
.widget
.AdapterView
; 
  37 import android
.widget
.AdapterView
.OnItemClickListener
; 
  38 import android
.widget
.GridView
; 
  39 import android
.widget
.ListAdapter
; 
  40 import android
.widget
.ListView
; 
  41 import android
.widget
.TextView
; 
  43 import com
.owncloud
.android
.R
; 
  44 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
; 
  45 import com
.owncloud
.android
.ui
.ExtendedListView
; 
  46 import com
.owncloud
.android
.ui
.activity
.OnEnforceableRefreshListener
; 
  47 import com
.owncloud
.android
.ui
.adapter
.FileListListAdapter
; 
  49 import third_parties
.in.srain
.cube
.GridViewWithHeaderAndFooter
; 
  52  * TODO extending SherlockListFragment instead of SherlockFragment 
  54 public class ExtendedListFragment 
extends Fragment
 
  55         implements OnItemClickListener
, OnEnforceableRefreshListener 
{ 
  57     private static final String TAG 
= ExtendedListFragment
.class.getSimpleName(); 
  59     private static final String KEY_SAVED_LIST_POSITION 
= "SAVED_LIST_POSITION"; 
  60     private static final String KEY_INDEXES 
= "INDEXES"; 
  61     private static final String KEY_FIRST_POSITIONS
= "FIRST_POSITIONS"; 
  62     private static final String KEY_TOPS 
= "TOPS"; 
  63     private static final String KEY_HEIGHT_CELL 
= "HEIGHT_CELL"; 
  64     private static final String KEY_EMPTY_LIST_MESSAGE 
= "EMPTY_LIST_MESSAGE"; 
  66     private SwipeRefreshLayout mRefreshListLayout
; 
  67     private SwipeRefreshLayout mRefreshGridLayout
; 
  68     private SwipeRefreshLayout mRefreshEmptyLayout
; 
  69     private TextView mEmptyListMessage
; 
  71     // Save the state of the scroll in browsing 
  72     private ArrayList
<Integer
> mIndexes
; 
  73     private ArrayList
<Integer
> mFirstPositions
; 
  74     private ArrayList
<Integer
> mTops
; 
  75     private int mHeightCell 
= 0; 
  77     private SwipeRefreshLayout
.OnRefreshListener mOnRefreshListener 
= null
; 
  79     protected AbsListView mCurrentListView
; 
  80     private ExtendedListView mListView
; 
  81     private View mListFooterView
; 
  82     private GridViewWithHeaderAndFooter mGridView
; 
  83     private View mGridFooterView
; 
  85     private ListAdapter mAdapter
; 
  87     protected void setListAdapter(ListAdapter listAdapter
) { 
  88         mAdapter 
= listAdapter
; 
  89         if (android
.os
.Build
.VERSION
.SDK_INT 
>= Build
.VERSION_CODES
.HONEYCOMB
) { 
  90             mCurrentListView
.setAdapter(listAdapter
); 
  92             ((ListView
)mCurrentListView
).setAdapter(listAdapter
); 
  95         mCurrentListView
.invalidate(); 
  98     protected AbsListView 
getListView() { 
  99         return mCurrentListView
; 
 103     protected void switchToGridView() { 
 104         if ((mCurrentListView 
== mListView
)) { 
 106             mListView
.setAdapter(null
); 
 107             mRefreshListLayout
.setVisibility(View
.GONE
); 
 109             if (mAdapter 
instanceof FileListListAdapter
) { 
 110                 ((FileListListAdapter
) mAdapter
).setGridMode(true
); 
 112             mGridView
.setAdapter(mAdapter
); 
 113             mRefreshGridLayout
.setVisibility(View
.VISIBLE
); 
 115             mCurrentListView 
= mGridView
; 
 119     protected void switchToListView() { 
 120         if (mCurrentListView 
== mGridView
) { 
 121             mGridView
.setAdapter(null
); 
 122             mRefreshGridLayout
.setVisibility(View
.GONE
); 
 124             if (mAdapter 
instanceof FileListListAdapter
) { 
 125                 ((FileListListAdapter
) mAdapter
).setGridMode(false
); 
 127             mListView
.setAdapter(mAdapter
); 
 128             mRefreshListLayout
.setVisibility(View
.VISIBLE
); 
 130             mCurrentListView 
= mListView
; 
 136     public View 
onCreateView(LayoutInflater inflater
, ViewGroup container
, 
 137                              Bundle savedInstanceState
) { 
 138         Log_OC
.d(TAG
, "onCreateView"); 
 141 //         AbsListView.MultiChoiceModeListener listener = new AbsListView.MultiChoiceModeListener() { 
 143 //            public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { 
 144 //                // Capture total checked items 
 145 //                final int checkedCount = mListView.getCheckedItemCount(); 
 146 //                // Set the CAB title according to total checked items 
 147 //                mode.setTitle(checkedCount + " Selected"); 
 148 //                // Calls toggleSelection method from ListViewAdapter Class 
 149 //                 // mAdapter.toggleSelection(position); 
 152 //                    mAdapter.setNewSelection(position,checked); 
 154 //                    mAdapter.removeSelection(position); 
 159 //            public boolean onCreateActionMode(ActionMode mode, Menu menu) { 
 160 //                mode.getMenuInflater().inflate(R.menu.context, menu); 
 165 //            public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 
 170 //            public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 
 175 //            public void onDestroyActionMode(ActionMode mode) { 
 176 //                // mAdapter.removeSelection(); 
 180         View v 
= inflater
.inflate(R
.layout
.list_fragment
, null
); 
 182         mListView 
= (ExtendedListView
)(v
.findViewById(R
.id
.list_root
)); 
 183         mListView
.setOnItemClickListener(this); 
 184         mListView
.setChoiceMode(ListView
.CHOICE_MODE_MULTIPLE_MODAL
); 
 185         // mListView.setMultiChoiceModeListener(listener); 
 186         mListFooterView 
= inflater
.inflate(R
.layout
.list_footer
, null
, false
); 
 188         mGridView 
= (GridViewWithHeaderAndFooter
) (v
.findViewById(R
.id
.grid_root
)); 
 189         mGridView
.setNumColumns(GridView
.AUTO_FIT
); 
 190         mGridView
.setOnItemClickListener(this); 
 191         mGridView
.setChoiceMode(ListView
.CHOICE_MODE_MULTIPLE_MODAL
); 
 193         // mGridView.setMultiChoiceModeListener(listener); 
 195         mGridFooterView 
= inflater
.inflate(R
.layout
.list_footer
, null
, false
); 
 197         if (savedInstanceState 
!= null
) { 
 198             int referencePosition 
= savedInstanceState
.getInt(KEY_SAVED_LIST_POSITION
); 
 199             if (mCurrentListView 
== mListView
) { 
 200                 Log_OC
.v(TAG
, "Setting and centering around list position " + referencePosition
); 
 201                 mListView
.setAndCenterSelection(referencePosition
); 
 203                 Log_OC
.v(TAG
, "Setting grid position " + referencePosition
); 
 204                 mGridView
.setSelection(referencePosition
); 
 208         // Pull-down to refresh layout 
 209         mRefreshListLayout 
= (SwipeRefreshLayout
) v
.findViewById(R
.id
.swipe_containing_list
); 
 210         mRefreshGridLayout 
= (SwipeRefreshLayout
) v
.findViewById(R
.id
.swipe_containing_grid
); 
 211         mRefreshEmptyLayout 
= (SwipeRefreshLayout
) v
.findViewById(R
.id
.swipe_containing_empty
); 
 212         mEmptyListMessage 
= (TextView
) v
.findViewById(R
.id
.empty_list_view
); 
 214         onCreateSwipeToRefresh(mRefreshListLayout
); 
 215         onCreateSwipeToRefresh(mRefreshGridLayout
); 
 216         onCreateSwipeToRefresh(mRefreshEmptyLayout
); 
 218         mListView
.setEmptyView(mRefreshEmptyLayout
); 
 219         mGridView
.setEmptyView(mRefreshEmptyLayout
); 
 221         mCurrentListView 
= mListView
;   // list as default 
 230     public void onActivityCreated(Bundle savedInstanceState
) { 
 231         super.onActivityCreated(savedInstanceState
); 
 233         if (savedInstanceState 
!= null
) { 
 234             mIndexes 
= savedInstanceState
.getIntegerArrayList(KEY_INDEXES
); 
 235             mFirstPositions 
= savedInstanceState
.getIntegerArrayList(KEY_FIRST_POSITIONS
); 
 236             mTops 
= savedInstanceState
.getIntegerArrayList(KEY_TOPS
); 
 237             mHeightCell 
= savedInstanceState
.getInt(KEY_HEIGHT_CELL
); 
 238             setMessageForEmptyList(savedInstanceState
.getString(KEY_EMPTY_LIST_MESSAGE
)); 
 241             mIndexes 
= new ArrayList
<Integer
>(); 
 242             mFirstPositions 
= new ArrayList
<Integer
>(); 
 243             mTops 
= new ArrayList
<Integer
>(); 
 250     public void onSaveInstanceState(Bundle savedInstanceState
) { 
 251         super.onSaveInstanceState(savedInstanceState
); 
 252         Log_OC
.d(TAG
, "onSaveInstanceState()"); 
 253         savedInstanceState
.putInt(KEY_SAVED_LIST_POSITION
, getReferencePosition()); 
 254         savedInstanceState
.putIntegerArrayList(KEY_INDEXES
, mIndexes
); 
 255         savedInstanceState
.putIntegerArrayList(KEY_FIRST_POSITIONS
, mFirstPositions
); 
 256         savedInstanceState
.putIntegerArrayList(KEY_TOPS
, mTops
); 
 257         savedInstanceState
.putInt(KEY_HEIGHT_CELL
, mHeightCell
); 
 258         savedInstanceState
.putString(KEY_EMPTY_LIST_MESSAGE
, getEmptyViewText()); 
 262      * Calculates the position of the item that will be used as a reference to 
 263      * reposition the visible items in the list when the device is turned to 
 266      * The current policy is take as a reference the visible item in the center 
 269      * @return The position in the list of the visible item in the center of the 
 272     protected int getReferencePosition() { 
 273         if (mCurrentListView 
!= null
) { 
 274             return (mCurrentListView
.getFirstVisiblePosition() + 
 275                     mCurrentListView
.getLastVisiblePosition()) / 2; 
 283      * Restore index and position 
 285     protected void restoreIndexAndTopPosition() { 
 286         if (mIndexes
.size() > 0) {   
 287             // needs to be checked; not every browse-up had a browse-down before  
 289             int index 
= mIndexes
.remove(mIndexes
.size() - 1); 
 290             final int firstPosition 
= mFirstPositions
.remove(mFirstPositions
.size() -1); 
 291             int top 
= mTops
.remove(mTops
.size() - 1); 
 293             Log_OC
.v(TAG
, "Setting selection to position: " + firstPosition 
+ "; top: " 
 294                     + top 
+ "; index: " + index
); 
 296             if (mCurrentListView 
== mListView
) { 
 297                 if (mHeightCell
*index 
<= mListView
.getHeight()) { 
 298                     mListView
.setSelectionFromTop(firstPosition
, top
); 
 300                     mListView
.setSelectionFromTop(index
, 0); 
 304                 if (mHeightCell
*index 
<= mGridView
.getHeight()) { 
 305                     mGridView
.setSelection(firstPosition
); 
 306                     //mGridView.smoothScrollToPosition(firstPosition); 
 308                     mGridView
.setSelection(index
); 
 309                     //mGridView.smoothScrollToPosition(index); 
 317      * Save index and top position 
 319     protected void saveIndexAndTopPosition(int index
) { 
 323         int firstPosition 
= mCurrentListView
.getFirstVisiblePosition(); 
 324         mFirstPositions
.add(firstPosition
); 
 326         View view 
= mCurrentListView
.getChildAt(0); 
 327         int top 
= (view 
== null
) ? 
0 : view
.getTop() ; 
 331         // Save the height of a cell 
 332         mHeightCell 
= (view 
== null 
|| mHeightCell 
!= 0) ? mHeightCell 
: view
.getHeight(); 
 337     public void onItemClick (AdapterView
<?
> parent
, View view
, int position
, long id
) { 
 342     public void onRefresh() { 
 343         mRefreshListLayout
.setRefreshing(false
); 
 344         mRefreshGridLayout
.setRefreshing(false
); 
 345         mRefreshEmptyLayout
.setRefreshing(false
); 
 347         if (mOnRefreshListener 
!= null
) { 
 348             mOnRefreshListener
.onRefresh(); 
 351     public void setOnRefreshListener(OnEnforceableRefreshListener listener
) { 
 352         mOnRefreshListener 
= listener
; 
 357      * Disables swipe gesture. 
 359      * Sets the 'enabled' state of the refresh layouts contained in the fragment. 
 361      * When 'false' is set, prevents user gestures but keeps the option to refresh programatically, 
 363      * @param   enabled     Desired state for capturing swipe gesture. 
 365     public void setSwipeEnabled(boolean enabled
) { 
 366         mRefreshListLayout
.setEnabled(enabled
); 
 367         mRefreshGridLayout
.setEnabled(enabled
); 
 368         mRefreshEmptyLayout
.setEnabled(enabled
); 
 372      * Set message for empty list view 
 374     public void setMessageForEmptyList(String message
) { 
 375         if (mEmptyListMessage 
!= null
) { 
 376             mEmptyListMessage
.setText(message
); 
 381      * Get the text of EmptyListMessage TextView 
 385     public String 
getEmptyViewText() { 
 386         return (mEmptyListMessage 
!= null
) ? mEmptyListMessage
.getText().toString() : ""; 
 389     private void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout
) { 
 390         // Colors in animations 
 391         refreshLayout
.setColorSchemeResources(R
.color
.color_accent
, R
.color
.primary
, 
 392                 R
.color
.primary_dark
); 
 394         refreshLayout
.setOnRefreshListener(this); 
 398     public void onRefresh(boolean ignoreETag
) { 
 399         mRefreshListLayout
.setRefreshing(false
); 
 400         mRefreshGridLayout
.setRefreshing(false
); 
 401         mRefreshEmptyLayout
.setRefreshing(false
); 
 403         if (mOnRefreshListener 
!= null
) { 
 404             mOnRefreshListener
.onRefresh(); 
 408     protected void setChoiceMode(int choiceMode
) { 
 409         if (android
.os
.Build
.VERSION
.SDK_INT 
>= Build
.VERSION_CODES
.HONEYCOMB
) { 
 410             mListView
.setChoiceMode(choiceMode
); 
 411             mGridView
.setChoiceMode(choiceMode
); 
 413             ((ListView
)mListView
).setChoiceMode(choiceMode
); 
 417     protected void registerForContextMenu() { 
 418         registerForContextMenu(mListView
); 
 419         registerForContextMenu(mGridView
); 
 420         mListView
.setOnCreateContextMenuListener(this); 
 421         mGridView
.setOnCreateContextMenuListener(this); 
 426      * To be called before setAdapter, or GridViewWithHeaderAndFooter will throw an exception 
 430     protected void setFooterEnabled(boolean enabled
) { 
 432             if (mGridView
.getFooterViewCount() == 0) { 
 433                 if (mGridFooterView
.getParent() != null 
) { 
 434                     ((ViewGroup
) mGridFooterView
.getParent()).removeView(mGridFooterView
); 
 436                 mGridView
.addFooterView(mGridFooterView
, null
, false
); 
 438             mGridFooterView
.invalidate(); 
 440             if (mListView
.getFooterViewsCount() == 0) { 
 441                 if (mListFooterView
.getParent() != null 
) { 
 442                     ((ViewGroup
) mListFooterView
.getParent()).removeView(mListFooterView
); 
 444                 mListView
.addFooterView(mListFooterView
, null
, false
); 
 446             mListFooterView
.invalidate(); 
 449             mGridView
.removeFooterView(mGridFooterView
); 
 450             mListView
.removeFooterView(mListFooterView
); 
 458     protected void setFooterText(String text
) { 
 459         if (text 
!= null 
&& text
.length() > 0) { 
 460             ((TextView
)mListFooterView
.findViewById(R
.id
.footerText
)).setText(text
); 
 461             ((TextView
)mGridFooterView
.findViewById(R
.id
.footerText
)).setText(text
); 
 462             setFooterEnabled(true
); 
 465             setFooterEnabled(false
);