mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
rewrite list item logic. Use a single custom LinearLayout subclass
for both the loading and loaded phases, toggling its state once the data's available. Reuse it: pay attention to what's passed into getView and only allocate when there's no existing View to reuse. Stop caching Views, as that defeats Android list logic that might limit in-memory representation to the subset that's visible on-screen, instead tracking a set of rowids whose data is known to be good as a way of quickly drawing when there's a refresh.
This commit is contained in:
parent
83b1d4c364
commit
7efbd2697d
5 changed files with 420 additions and 324 deletions
|
@ -3,95 +3,114 @@
|
|||
|
||||
|
||||
<!-- top-level layout is hozontal, with an image and another layout -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:longClickable="true"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:background="@android:drawable/list_selector_background"
|
||||
>
|
||||
<org.eehouse.android.xw4.GameListItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:longClickable="true"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:background="@android:drawable/list_selector_background"
|
||||
>
|
||||
|
||||
<ImageView android:id="@+id/msg_marker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:layout_weight="0"
|
||||
/>
|
||||
<TextView android:id="@+id/view_unloaded"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:gravity="center"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:text="@string/game_list_tmp"
|
||||
/>
|
||||
|
||||
<!-- this layout is vertical, holds everything but the status
|
||||
icon[s] (plural later) -->
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<!-- This is the game name and expander -->
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<org.eehouse.android.xw4.ExpiringTextView
|
||||
android:id="@+id/game_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<ImageButton android:id="@+id/expander"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/expander_ic_maximized"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- This is everything below the name (which can be hidden) -->
|
||||
<LinearLayout android:id="@+id/hideable"
|
||||
<LinearLayout android:id="@+id/view_loaded"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4sp">
|
||||
android:visibility="gone"
|
||||
>
|
||||
|
||||
<!-- Player list plus connection status -->
|
||||
<LinearLayout android:id="@+id/player_list"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginRight="4dip"
|
||||
/> <!-- end players column -->
|
||||
<ImageView android:id="@+id/msg_marker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:layout_weight="0"
|
||||
/>
|
||||
|
||||
<!-- holds right column. Could hold more... -->
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView android:id="@+id/modtime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
/>
|
||||
<TextView android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<!-- this layout is vertical, holds everything but the status
|
||||
icon[s] (plural later) -->
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<!-- This is the game name and expander -->
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<org.eehouse.android.xw4.ExpiringTextView
|
||||
android:id="@+id/game_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<ImageButton android:id="@+id/expander"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/expander_ic_maximized"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- This is everything below the name (which can be hidden) -->
|
||||
<LinearLayout android:id="@+id/hideable"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4sp">
|
||||
|
||||
<!-- Player list plus connection status -->
|
||||
<LinearLayout android:id="@+id/player_list"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginRight="4dip"
|
||||
/> <!-- end players column -->
|
||||
|
||||
<!-- holds right column. Could hold more... -->
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView android:id="@+id/modtime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
/>
|
||||
<TextView android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView android:id="@+id/role"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView android:id="@+id/role"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</org.eehouse.android.xw4.GameListItem>
|
||||
|
|
|
@ -35,7 +35,7 @@ import android.widget.TextView;
|
|||
import java.io.FileInputStream;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap; // class is not synchronized
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
@ -46,10 +46,6 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
|||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
|
||||
public class GameListAdapter extends XWListAdapter {
|
||||
private Context m_context;
|
||||
private LayoutInflater m_factory;
|
||||
private int m_fieldID;
|
||||
private Handler m_handler;
|
||||
private static final boolean s_isFire;
|
||||
private static Random s_random;
|
||||
static {
|
||||
|
@ -59,79 +55,35 @@ public class GameListAdapter extends XWListAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private class ViewInfo implements View.OnClickListener {
|
||||
private View m_view;
|
||||
private View m_hideable;
|
||||
private ExpiringTextView m_name;
|
||||
private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
|
||||
private long m_rowid;
|
||||
private long m_lastMoveTime;
|
||||
private ImageButton m_expandButton;
|
||||
|
||||
public ViewInfo( View view, long rowid )
|
||||
{
|
||||
m_view = view;
|
||||
m_rowid = rowid;
|
||||
m_lastMoveTime = 0;
|
||||
}
|
||||
|
||||
public ViewInfo( View view, long rowid, boolean expanded,
|
||||
long lastMoveTime, boolean haveTurn,
|
||||
boolean haveTurnLocal ) {
|
||||
this( view, rowid );
|
||||
m_expanded = expanded;
|
||||
m_lastMoveTime = lastMoveTime;
|
||||
m_haveTurn = haveTurn;
|
||||
m_haveTurnLocal = haveTurnLocal;
|
||||
m_hideable = (LinearLayout)view.findViewById( R.id.hideable );
|
||||
m_name = (ExpiringTextView)m_view.findViewById( R.id.game_name );
|
||||
m_expandButton = (ImageButton)view.findViewById( R.id.expander );
|
||||
m_expandButton.setOnClickListener( this );
|
||||
showHide();
|
||||
}
|
||||
|
||||
private void showHide()
|
||||
{
|
||||
m_expandButton.setImageResource( m_expanded ?
|
||||
R.drawable.expander_ic_maximized :
|
||||
R.drawable.expander_ic_minimized);
|
||||
m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
|
||||
|
||||
m_name.setBackgroundColor( android.R.color.transparent );
|
||||
m_name.setPct( m_handler, m_haveTurn && !m_expanded,
|
||||
m_haveTurnLocal, m_lastMoveTime );
|
||||
}
|
||||
|
||||
public void onClick( View view ) {
|
||||
m_expanded = !m_expanded;
|
||||
DBUtils.setExpanded( m_rowid, m_expanded );
|
||||
showHide();
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<Long,ViewInfo> m_viewsCache;
|
||||
private Context m_context;
|
||||
private LayoutInflater m_factory;
|
||||
private int m_fieldID;
|
||||
private Handler m_handler;
|
||||
private DateFormat m_df;
|
||||
private LoadItemCB m_cb;
|
||||
|
||||
// Track those rows known to be good. If a rowid is not in this
|
||||
// set, assume it must be loaded. Add rowids to this set as
|
||||
// they're loaded, and remove one when when it must be redrawn.
|
||||
private HashSet<Long> m_loadedRows;
|
||||
|
||||
public interface LoadItemCB {
|
||||
public void itemLoaded( long rowid );
|
||||
public void itemClicked( long rowid );
|
||||
}
|
||||
|
||||
private class LoadItemTask extends AsyncTask<Void, Void, Void> {
|
||||
private long m_rowid;
|
||||
private class LoadItemTask extends AsyncTask<Void, Void, GameSummary> {
|
||||
private GameListItem m_view;
|
||||
private Context m_context;
|
||||
// private int m_id;
|
||||
public LoadItemTask( Context context, long rowid/*, int id*/ )
|
||||
public LoadItemTask( Context context, GameListItem view )
|
||||
{
|
||||
DbgUtils.logf( "Creating LoadItemTask for row %d",
|
||||
view.getRowID() );
|
||||
m_context = context;
|
||||
m_rowid = rowid;
|
||||
// m_id = id;
|
||||
m_view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground( Void... unused )
|
||||
protected GameSummary doInBackground( Void... unused )
|
||||
{
|
||||
// Without this, on the Fire only the last item in the
|
||||
// list it tappable. Likely my fault, but this seems to
|
||||
|
@ -143,133 +95,26 @@ public class GameListAdapter extends XWListAdapter {
|
|||
} catch ( Exception e ) {
|
||||
}
|
||||
}
|
||||
View layout = m_factory.inflate( R.layout.game_list_item, null );
|
||||
boolean hideTitle = false;//CommonPrefs.getHideTitleBar(m_context);
|
||||
GameSummary summary = DBUtils.getSummary( m_context, m_rowid, 1500 );
|
||||
if ( null == summary ) {
|
||||
m_rowid = -1;
|
||||
} else {
|
||||
String state = summary.summarizeState();
|
||||
|
||||
TextView view = (TextView)layout.findViewById( R.id.game_name );
|
||||
if ( hideTitle ) {
|
||||
view.setVisibility( View.GONE );
|
||||
} else {
|
||||
String value = null;
|
||||
switch ( m_fieldID ) {
|
||||
case R.string.game_summary_field_empty:
|
||||
break;
|
||||
case R.string.game_summary_field_language:
|
||||
value =
|
||||
DictLangCache.getLangName( m_context,
|
||||
summary.dictLang );
|
||||
break;
|
||||
case R.string.game_summary_field_opponents:
|
||||
value = summary.playerNames();
|
||||
break;
|
||||
case R.string.game_summary_field_state:
|
||||
value = state;
|
||||
break;
|
||||
}
|
||||
|
||||
String name = GameUtils.getName( m_context, m_rowid );
|
||||
|
||||
if ( null != value ) {
|
||||
value = m_context.getString( R.string.str_game_namef,
|
||||
name, value );
|
||||
} else {
|
||||
value = name;
|
||||
}
|
||||
|
||||
view.setText( value );
|
||||
}
|
||||
|
||||
layout.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View v ) {
|
||||
m_cb.itemClicked( m_rowid );
|
||||
}
|
||||
} );
|
||||
|
||||
LinearLayout list =
|
||||
(LinearLayout)layout.findViewById( R.id.player_list );
|
||||
boolean haveATurn = false;
|
||||
boolean haveALocalTurn = false;
|
||||
boolean[] isLocal = new boolean[1];
|
||||
for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
|
||||
ExpiringLinearLayout tmp = (ExpiringLinearLayout)
|
||||
m_factory.inflate( R.layout.player_list_elem, null );
|
||||
view = (TextView)tmp.findViewById( R.id.item_name );
|
||||
view.setText( summary.summarizePlayer( ii ) );
|
||||
view = (TextView)tmp.findViewById( R.id.item_score );
|
||||
view.setText( String.format( " %d", summary.scores[ii] ) );
|
||||
boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
|
||||
if ( thisHasTurn ) {
|
||||
haveATurn = true;
|
||||
if ( isLocal[0] ) {
|
||||
haveALocalTurn = true;
|
||||
}
|
||||
}
|
||||
tmp.setPct( m_handler, thisHasTurn, isLocal[0],
|
||||
summary.lastMoveTime );
|
||||
list.addView( tmp, ii );
|
||||
}
|
||||
|
||||
view = (TextView)layout.findViewById( R.id.state );
|
||||
view.setText( state );
|
||||
view = (TextView)layout.findViewById( R.id.modtime );
|
||||
long lastMoveTime = summary.lastMoveTime;
|
||||
lastMoveTime *= 1000;
|
||||
view.setText( m_df.format( new Date( lastMoveTime ) ) );
|
||||
|
||||
int iconID;
|
||||
ImageView marker =
|
||||
(ImageView)layout.findViewById( R.id.msg_marker );
|
||||
CommsConnType conType = summary.conType;
|
||||
if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
|
||||
iconID = R.drawable.relaygame;
|
||||
} else if ( CommsConnType.COMMS_CONN_BT == conType ) {
|
||||
iconID = android.R.drawable.stat_sys_data_bluetooth;
|
||||
} else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
|
||||
iconID = android.R.drawable.sym_action_chat;
|
||||
} else {
|
||||
iconID = R.drawable.sologame;
|
||||
}
|
||||
marker.setImageResource( iconID );
|
||||
|
||||
view = (TextView)layout.findViewById( R.id.role );
|
||||
String roleSummary = summary.summarizeRole();
|
||||
if ( null != roleSummary ) {
|
||||
view.setText( roleSummary );
|
||||
} else {
|
||||
view.setVisibility( View.GONE );
|
||||
}
|
||||
|
||||
boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
|
||||
ViewInfo vi = new ViewInfo( layout, m_rowid, expanded,
|
||||
summary.lastMoveTime, haveATurn,
|
||||
haveALocalTurn );
|
||||
if ( XWApp.DEBUG ) {
|
||||
DbgUtils.logf( "created new view for rowid %d", m_rowid );
|
||||
}
|
||||
synchronized( m_viewsCache ) {
|
||||
m_viewsCache.put( m_rowid, vi );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
long rowid = m_view.getRowID();
|
||||
GameSummary summary = DBUtils.getSummary( m_context, rowid, 1500 );
|
||||
return summary;
|
||||
} // doInBackground
|
||||
|
||||
@Override
|
||||
protected void onPostExecute( Void unused )
|
||||
protected void onPostExecute( GameSummary summary )
|
||||
{
|
||||
// DbgUtils.logf( "onPostExecute(rowid=%d)", m_rowid );
|
||||
if ( -1 != m_rowid ) {
|
||||
m_cb.itemLoaded( m_rowid );
|
||||
}
|
||||
setData( m_view, summary );
|
||||
setLoaded( m_view.getRowID() );
|
||||
m_view.setLoaded( true );
|
||||
|
||||
DbgUtils.logf( "LoadItemTask for row %d finished",
|
||||
m_view.getRowID() );
|
||||
}
|
||||
} // class LoadItemTask
|
||||
|
||||
public GameListAdapter( Context context, Handler handler, LoadItemCB cb ) {
|
||||
public GameListAdapter( Context context, Handler handler, LoadItemCB cb,
|
||||
String fieldName ) {
|
||||
super( DBUtils.gamesList(context).length );
|
||||
m_context = context;
|
||||
m_handler = handler;
|
||||
|
@ -278,62 +123,92 @@ public class GameListAdapter extends XWListAdapter {
|
|||
m_df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
|
||||
DateFormat.SHORT );
|
||||
|
||||
m_viewsCache = new HashMap<Long,ViewInfo>();
|
||||
m_loadedRows = new HashSet<Long>();
|
||||
m_fieldID = fieldToID( fieldName );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return DBUtils.gamesList(m_context).length;
|
||||
}
|
||||
|
||||
public Object getItem( int position )
|
||||
|
||||
// Views. A view depends on a summary, which takes time to load.
|
||||
// When one needs loading it's done via an async task.
|
||||
public View getView( int position, View convertView, ViewGroup parent )
|
||||
{
|
||||
final long rowid = DBUtils.gamesList(m_context)[position];
|
||||
View layout;
|
||||
boolean haveLayout = false;
|
||||
synchronized( m_viewsCache ) {
|
||||
ViewInfo vi = m_viewsCache.get( rowid );
|
||||
haveLayout = null != vi;
|
||||
if ( haveLayout ) {
|
||||
layout = vi.m_view;
|
||||
} else {
|
||||
layout = m_factory.inflate( R.layout.game_list_tmp, null );
|
||||
vi = new ViewInfo( layout, rowid );
|
||||
m_viewsCache.put( rowid, vi );
|
||||
GameListItem result;
|
||||
boolean mustLoad = false;
|
||||
if ( null == convertView ) {
|
||||
result = (GameListItem)
|
||||
m_factory.inflate( R.layout.game_list_item, null );
|
||||
result.setRowID( DBUtils.gamesList(m_context)[position] );
|
||||
mustLoad = true;
|
||||
} else {
|
||||
result = (GameListItem)convertView;
|
||||
long rowid = result.getRowID();
|
||||
if ( isDirty(rowid) || !result.isLoaded() ) {
|
||||
mustLoad = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !haveLayout ) {
|
||||
new LoadItemTask( m_context, rowid/*, ++m_taskCounter*/ ).execute();
|
||||
if ( mustLoad ) {
|
||||
new LoadItemTask( m_context, result ).execute();
|
||||
}
|
||||
|
||||
// this doesn't work. Rather, it breaks highlighting because
|
||||
// the background, if we don't set it, is a more complicated
|
||||
// object like @android:drawable/list_selector_background. I
|
||||
// tried calling getBackground(), expecting to get a Drawable
|
||||
// I could then clone and modify, but null comes back. So
|
||||
// layout must be inheriting its background from elsewhere or
|
||||
// it gets set later, during layout.
|
||||
// if ( (position%2) == 0 ) {
|
||||
// layout.setBackgroundColor( 0xFF3F3F3F );
|
||||
// }
|
||||
|
||||
return layout;
|
||||
} // getItem
|
||||
|
||||
public View getView( int position, View convertView, ViewGroup parent ) {
|
||||
return (View)getItem( position );
|
||||
return result;
|
||||
}
|
||||
|
||||
public void inval( long rowid )
|
||||
{
|
||||
synchronized( m_viewsCache ) {
|
||||
m_viewsCache.remove( rowid );
|
||||
synchronized( m_loadedRows ) {
|
||||
m_loadedRows.remove( rowid );
|
||||
}
|
||||
}
|
||||
|
||||
private void dirtyAll()
|
||||
{
|
||||
synchronized( m_loadedRows ) {
|
||||
m_loadedRows.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDirty( long rowid )
|
||||
{
|
||||
synchronized( m_loadedRows ) {
|
||||
return ! m_loadedRows.contains( rowid );
|
||||
}
|
||||
}
|
||||
|
||||
private void setLoaded( long rowid )
|
||||
{
|
||||
synchronized( m_loadedRows ) {
|
||||
m_loadedRows.add( rowid );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setField( String fieldName )
|
||||
{
|
||||
boolean changed = false;
|
||||
int newID = fieldToID( fieldName );
|
||||
if ( -1 == newID ) {
|
||||
if ( XWApp.DEBUG ) {
|
||||
DbgUtils.logf( "GameListAdapter.setField(): unable to match"
|
||||
+ " fieldName %s", fieldName );
|
||||
}
|
||||
} else if ( m_fieldID != newID ) {
|
||||
if ( XWApp.DEBUG ) {
|
||||
DbgUtils.logf( "setField: clearing views cache for change"
|
||||
+ " from %d to %d", m_fieldID, newID );
|
||||
}
|
||||
m_fieldID = newID;
|
||||
dirtyAll();
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private int fieldToID( String fieldName )
|
||||
{
|
||||
int[] ids = {
|
||||
R.string.game_summary_field_empty
|
||||
,R.string.game_summary_field_language
|
||||
|
@ -347,21 +222,109 @@ public class GameListAdapter extends XWListAdapter {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ( -1 == result ) {
|
||||
if ( XWApp.DEBUG ) {
|
||||
DbgUtils.logf( "GameListAdapter.setField(): unable to match"
|
||||
+ " fieldName %s", fieldName );
|
||||
}
|
||||
} else if ( m_fieldID != result ) {
|
||||
if ( XWApp.DEBUG ) {
|
||||
DbgUtils.logf( "setField: clearing views cache for change"
|
||||
+ " from %d to %d", m_fieldID, result );
|
||||
}
|
||||
m_viewsCache.clear();
|
||||
m_fieldID = result;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setData( GameListItem layout, GameSummary summary )
|
||||
{
|
||||
if ( null != summary ) {
|
||||
final long rowid = layout.getRowID();
|
||||
String state = summary.summarizeState();
|
||||
|
||||
TextView view = (TextView)layout.findViewById( R.id.game_name );
|
||||
String value = null;
|
||||
switch ( m_fieldID ) {
|
||||
case R.string.game_summary_field_empty:
|
||||
break;
|
||||
case R.string.game_summary_field_language:
|
||||
value =
|
||||
DictLangCache.getLangName( m_context,
|
||||
summary.dictLang );
|
||||
break;
|
||||
case R.string.game_summary_field_opponents:
|
||||
value = summary.playerNames();
|
||||
break;
|
||||
case R.string.game_summary_field_state:
|
||||
value = state;
|
||||
break;
|
||||
}
|
||||
|
||||
String name = GameUtils.getName( m_context, rowid );
|
||||
|
||||
if ( null != value ) {
|
||||
value = m_context.getString( R.string.str_game_namef,
|
||||
name, value );
|
||||
} else {
|
||||
value = name;
|
||||
}
|
||||
|
||||
view.setText( value );
|
||||
|
||||
layout.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View v ) {
|
||||
m_cb.itemClicked( rowid );
|
||||
}
|
||||
} );
|
||||
|
||||
LinearLayout list =
|
||||
(LinearLayout)layout.findViewById( R.id.player_list );
|
||||
boolean haveATurn = false;
|
||||
boolean haveALocalTurn = false;
|
||||
boolean[] isLocal = new boolean[1];
|
||||
for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
|
||||
ExpiringLinearLayout tmp = (ExpiringLinearLayout)
|
||||
m_factory.inflate( R.layout.player_list_elem, null );
|
||||
view = (TextView)tmp.findViewById( R.id.item_name );
|
||||
view.setText( summary.summarizePlayer( ii ) );
|
||||
view = (TextView)tmp.findViewById( R.id.item_score );
|
||||
view.setText( String.format( " %d", summary.scores[ii] ) );
|
||||
boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
|
||||
if ( thisHasTurn ) {
|
||||
haveATurn = true;
|
||||
if ( isLocal[0] ) {
|
||||
haveALocalTurn = true;
|
||||
}
|
||||
}
|
||||
tmp.setPct( m_handler, thisHasTurn, isLocal[0],
|
||||
summary.lastMoveTime );
|
||||
list.addView( tmp, ii );
|
||||
}
|
||||
|
||||
view = (TextView)layout.findViewById( R.id.state );
|
||||
view.setText( state );
|
||||
view = (TextView)layout.findViewById( R.id.modtime );
|
||||
long lastMoveTime = summary.lastMoveTime;
|
||||
lastMoveTime *= 1000;
|
||||
view.setText( m_df.format( new Date( lastMoveTime ) ) );
|
||||
|
||||
int iconID;
|
||||
ImageView marker =
|
||||
(ImageView)layout.findViewById( R.id.msg_marker );
|
||||
CommsConnType conType = summary.conType;
|
||||
if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
|
||||
iconID = R.drawable.relaygame;
|
||||
} else if ( CommsConnType.COMMS_CONN_BT == conType ) {
|
||||
iconID = android.R.drawable.stat_sys_data_bluetooth;
|
||||
} else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
|
||||
iconID = android.R.drawable.sym_action_chat;
|
||||
} else {
|
||||
iconID = R.drawable.sologame;
|
||||
}
|
||||
marker.setImageResource( iconID );
|
||||
|
||||
view = (TextView)layout.findViewById( R.id.role );
|
||||
String roleSummary = summary.summarizeRole();
|
||||
if ( null != roleSummary ) {
|
||||
view.setText( roleSummary );
|
||||
} else {
|
||||
view.setVisibility( View.GONE );
|
||||
}
|
||||
|
||||
boolean expanded = DBUtils.getExpanded( m_context, rowid );
|
||||
|
||||
layout.update( m_handler, expanded, summary.lastMoveTime,
|
||||
haveATurn, haveALocalTurn );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2009-2012 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class GameListItem extends LinearLayout
|
||||
implements View.OnClickListener {
|
||||
|
||||
private Context m_context;
|
||||
private boolean m_loaded;
|
||||
private long m_rowid;
|
||||
private View m_hideable;
|
||||
private ExpiringTextView m_name;
|
||||
private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
|
||||
private long m_lastMoveTime;
|
||||
private ImageButton m_expandButton;
|
||||
private Handler m_handler;
|
||||
|
||||
public GameListItem( Context cx, AttributeSet as )
|
||||
{
|
||||
super( cx, as );
|
||||
m_context = cx;
|
||||
m_loaded = false;
|
||||
m_rowid = DBUtils.ROWID_NOTFOUND;
|
||||
m_lastMoveTime = 0;
|
||||
}
|
||||
|
||||
public void update( Handler handler, boolean expanded,
|
||||
long lastMoveTime, boolean haveTurn,
|
||||
boolean haveTurnLocal )
|
||||
{
|
||||
m_handler = handler;
|
||||
m_expanded = expanded;
|
||||
m_lastMoveTime = lastMoveTime;
|
||||
m_haveTurn = haveTurn;
|
||||
m_haveTurnLocal = haveTurnLocal;
|
||||
m_hideable = (LinearLayout)findViewById( R.id.hideable );
|
||||
m_name = (ExpiringTextView)findViewById( R.id.game_name );
|
||||
m_expandButton = (ImageButton)findViewById( R.id.expander );
|
||||
m_expandButton.setOnClickListener( this );
|
||||
showHide();
|
||||
}
|
||||
|
||||
public void setLoaded( boolean loaded )
|
||||
{
|
||||
if ( m_loaded != loaded ) {
|
||||
m_loaded = loaded;
|
||||
// This should be enough to invalidate
|
||||
findViewById( R.id.view_unloaded )
|
||||
.setVisibility( loaded ? View.GONE : View.VISIBLE );
|
||||
findViewById( R.id.view_loaded )
|
||||
.setVisibility( loaded ? View.VISIBLE : View.GONE );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLoaded()
|
||||
{
|
||||
return m_loaded;
|
||||
}
|
||||
|
||||
public void setRowID( long rowid )
|
||||
{
|
||||
m_rowid = rowid;
|
||||
}
|
||||
|
||||
public long getRowID()
|
||||
{
|
||||
return m_rowid;
|
||||
}
|
||||
|
||||
// View.OnClickListener interface
|
||||
public void onClick( View view ) {
|
||||
m_expanded = !m_expanded;
|
||||
DBUtils.setExpanded( m_rowid, m_expanded );
|
||||
showHide();
|
||||
}
|
||||
|
||||
private void showHide()
|
||||
{
|
||||
m_expandButton.setImageResource( m_expanded ?
|
||||
R.drawable.expander_ic_maximized :
|
||||
R.drawable.expander_ic_minimized);
|
||||
m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
|
||||
|
||||
m_name.setBackgroundColor( android.R.color.transparent );
|
||||
m_name.setPct( m_handler, m_haveTurn && !m_expanded,
|
||||
m_haveTurnLocal, m_lastMoveTime );
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -282,7 +282,8 @@ public class GamesList extends XWListActivity
|
|||
}
|
||||
});
|
||||
|
||||
m_adapter = new GameListAdapter( this, new Handler(), this );
|
||||
String field = CommonPrefs.getSummaryField( this );
|
||||
m_adapter = new GameListAdapter( this, new Handler(), this, field );
|
||||
setListAdapter( m_adapter );
|
||||
|
||||
NetUtils.informOfDeaths( this );
|
||||
|
@ -391,11 +392,6 @@ public class GamesList extends XWListActivity
|
|||
}
|
||||
|
||||
// GameListAdapter.LoadItemCB interface
|
||||
public void itemLoaded( long rowid )
|
||||
{
|
||||
onContentChanged();
|
||||
}
|
||||
|
||||
public void itemClicked( long rowid )
|
||||
{
|
||||
// We need a way to let the user get back to the basic-config
|
||||
|
|
|
@ -41,8 +41,11 @@ public abstract class XWListAdapter implements ListAdapter {
|
|||
public boolean areAllItemsEnabled() { return true; }
|
||||
public boolean isEnabled( int position ) { return true; }
|
||||
public int getCount() { return m_count; }
|
||||
public Object getItem( int position ) { return null; }
|
||||
public long getItemId(int position) { return position; }
|
||||
public int getItemViewType(int position) { return 0; }
|
||||
public int getItemViewType( int position ) {
|
||||
return ListAdapter.IGNORE_ITEM_VIEW_TYPE;
|
||||
}
|
||||
public int getViewTypeCount() { return 1; }
|
||||
public boolean hasStableIds() { return true; }
|
||||
public boolean isEmpty() { return getCount() == 0; }
|
||||
|
|
Loading…
Add table
Reference in a new issue