lots of changes toward grouping games in user-definable groups.

Creation and movement between work.  Deletion crashes.  Expansion
doesn't stick.  All's rough.
This commit is contained in:
Eric House 2012-11-19 07:41:15 -08:00
parent 2779139e75
commit 82c39489f0
13 changed files with 847 additions and 124 deletions

View file

@ -27,12 +27,12 @@
/>
</LinearLayout>
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
/>
<ExpandableListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
/>
<TextView android:id="@+id/empty_list_msg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@ -41,11 +41,23 @@
android:text="@string/empty_list_msg"
/>
<Button android:id="@+id/new_game"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/button_new_game"
/>
<LinearLayout android:id="@+id/new_buttons"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button android:id="@+id/new_game"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/button_new_game"
/>
<Button android:id="@+id/new_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="@string/button_new_group"
/>
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/list_group_default"
android:title="@string/list_group_default"
/>
<item android:id="@+id/list_group_rename"
android:title="@string/list_group_rename"
/>
<item android:id="@+id/list_group_delete"
android:title="@string/list_group_delete"
/>
</menu>

View file

@ -7,6 +7,9 @@
<item android:id="@+id/list_item_rename"
android:title="@string/list_item_rename"
/>
<item android:id="@+id/list_item_move"
android:title="@string/list_item_move"
/>
<item android:id="@+id/list_item_delete"
android:title="@string/list_item_delete"
/>

View file

@ -71,6 +71,7 @@
<string name="key_gcmvers_regid">key_gcmvers_regid</string>
<string name="key_relay_regid">key_relay_regid</string>
<string name="key_checked_sms">key_checked_sms</string>
<string name="key_default_group">key_default_group</string>
<string name="key_notagain_sync">key_notagain_sync</string>
<string name="key_notagain_chat">key_notagain_chat</string>

View file

@ -27,6 +27,7 @@
menuitem in main games-list screen's menu. (The botton can
be hidden in the same way as the above text.) -->
<string name="button_new_game">Add game</string>
<string name="button_new_group">Add group</string>
<!-- When the game list is empty and the above messages and button
are hidden via preferences, this text is shown -->
@ -142,6 +143,9 @@
<string name="list_item_config">Game settings...</string>
<!-- pulls up dialog to rename (change name of) the selected game -->
<string name="list_item_rename">Rename...</string>
<!-- pulls up dialog to change the group of the selected game -->
<string name="list_item_move">Change group...</string>
<!-- pulls up dialog to delete the selected game -->
<string name="list_item_delete">Delete</string>
<!-- pulls up dialog to reset the selected game, that is to remove
@ -2124,4 +2128,21 @@
<string name="default_loc_summary">(Not in external/sdcard memory)</string>
<string name="download_path_title">Downloads Directory</string>
<string name="newgroup_label">Name your new group:</string>
<string name="list_group_delete">Delete group</string>
<string name="list_group_rename">Rename group</string>
<string name="list_group_default">Put new games here</string>
<string name="group_cur_games">My games</string>
<string name="group_new_games">New games</string>
<string name="group_confirm_del">Are you sure you want to delete
this group?</string>
<string name="group_confirm_delf">\u0020(It contains %d game[s],
which will also be deleted.)</string>
<string name="rename_group_label">Change the name of this group to:</string>
<string name="game_rename_group_title">Rename group</string>
</resources>

View file

@ -20,9 +20,10 @@
package org.eehouse.android.xw4;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
@ -30,8 +31,9 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME_OBITS = "obits";
public static final String TABLE_NAME_DICTBROWSE = "dictbrowse";
public static final String TABLE_NAME_DICTINFO = "dictinfo";
public static final String TABLE_NAME_GROUPS = "groups";
private static final String DB_NAME = "xwdb";
private static final int DB_VERSION = 14;
private static final int DB_VERSION = 15;
public static final String GAME_NAME = "GAME_NAME";
public static final String NUM_MOVES = "NUM_MOVES";
@ -60,7 +62,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String SEED = "SEED";
public static final String SMSPHONE = "SMSPHONE";
public static final String LASTMOVE = "LASTMOVE";
public static final String GROUPID = "GROUPID";
public static final String DICTNAME = "DICTNAME";
public static final String MD5SUM = "MD5SUM";
@ -76,6 +78,11 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String CREATE_TIME = "CREATE_TIME";
public static final String LASTPLAY_TIME = "LASTPLAY_TIME";
public static final String GROUPNAME = "GROUPNAME";
public static final String EXPANDED = "EXPANDED";
private Context m_context;
private static final String[] s_summaryColsAndTypes = {
GAME_NAME, "TEXT"
,NUM_MOVES, "INTEGER"
@ -99,6 +106,7 @@ public class DBHelper extends SQLiteOpenHelper {
,GAMEID, "INTEGER"
,REMOTEDEVS, "TEXT"
,LASTMOVE, "INTEGER DEFAULT 0"
,GROUPID, "INTEGER"
// HASMSGS: sqlite doesn't have bool; use 0 and 1
,HASMSGS, "INTEGER DEFAULT 0"
,CONTRACTED, "INTEGER DEFAULT 0"
@ -131,9 +139,15 @@ public class DBHelper extends SQLiteOpenHelper {
,ITERPREFIX, "TEXT"
};
private static final String[] s_groupsSchema = {
GROUPNAME, "TEXT"
,EXPANDED, "INTEGER(0)"
};
public DBHelper( Context context )
{
super( context, DB_NAME, null, DB_VERSION );
m_context = context;
}
public static String getDBName()
@ -148,6 +162,7 @@ public class DBHelper extends SQLiteOpenHelper {
createTable( db, TABLE_NAME_OBITS, s_obitsColsAndTypes );
createTable( db, TABLE_NAME_DICTINFO, s_dictInfoColsAndTypes );
createTable( db, TABLE_NAME_DICTBROWSE, s_dictBrowseColsAndTypes );
createGroupsTable( db );
}
@Override
@ -177,9 +192,11 @@ public class DBHelper extends SQLiteOpenHelper {
case 12:
createTable( db, TABLE_NAME_DICTINFO, s_dictInfoColsAndTypes );
createTable( db, TABLE_NAME_DICTBROWSE, s_dictBrowseColsAndTypes );
case 13:
addSumColumn( db, LASTMOVE );
case 14:
addSumColumn( db, GROUPID );
createGroupsTable( db );
// nothing yet
break;
default:
@ -221,4 +238,26 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL( query.toString() );
}
private void createGroupsTable( SQLiteDatabase db )
{
createTable( db, TABLE_NAME_GROUPS, s_groupsSchema );
// Create an empty group name
ContentValues values = new ContentValues();
values.put( GROUPNAME, m_context.getString(R.string.group_cur_games) );
values.put( EXPANDED, 1 );
long curGroup = db.insert( TABLE_NAME_GROUPS, null, values );
values = new ContentValues();
values.put( GROUPNAME, m_context.getString(R.string.group_new_games) );
values.put( EXPANDED, 0 );
long newGroup = db.insert( TABLE_NAME_GROUPS, null, values );
// place all existing games in the initial unnamed group
values = new ContentValues();
values.put( GROUPID, curGroup );
db.update( DBHelper.TABLE_NAME_SUM, values, null, null );
XWPrefs.setDefaultNewGameGroup( m_context, newGroup );
}
}

View file

@ -364,18 +364,9 @@ public class DBUtils {
private static void setInt( long rowid, String column, int value )
{
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
String selection = String.format( ROW_ID_FMT, rowid );
ContentValues values = new ContentValues();
values.put( column, value );
int result = db.update( DBHelper.TABLE_NAME_SUM,
values, selection, null );
Assert.assertTrue( result == 1 );
db.close();
}
ContentValues values = new ContentValues();
values.put( column, value );
updateRow( null, DBHelper.TABLE_NAME_SUM, rowid, values );
}
public static void setMsgFlags( long rowid, int flags )
@ -687,6 +678,8 @@ public class DBUtils {
long timestamp = new Date().getTime();
values.put( DBHelper.CREATE_TIME, timestamp );
values.put( DBHelper.LASTPLAY_TIME, timestamp );
values.put( DBHelper.GROUPID,
XWPrefs.getDefaultNewGameGroup( context ) );
long rowid = db.insert( DBHelper.TABLE_NAME_SUM, null, values );
@ -834,21 +827,9 @@ public class DBUtils {
public static void setName( Context context, long rowid, String name )
{
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
String selection = String.format( ROW_ID_FMT, rowid );
ContentValues values = new ContentValues();
values.put( DBHelper.GAME_NAME, name );
int result = db.update( DBHelper.TABLE_NAME_SUM,
values, selection, null );
db.close();
if ( 0 == result ) {
DbgUtils.logf( "setName(%d,%s) failed", rowid, name );
}
}
ContentValues values = new ContentValues();
values.put( DBHelper.GAME_NAME, name );
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
}
public static HistoryPair[] getChatHistory( Context context, long rowid )
@ -868,6 +849,163 @@ public class DBUtils {
return result;
}
// Groups stuff
public static class GameGroupInfo {
public long m_id;
public boolean m_expanded;
public GameGroupInfo( long id, boolean expanded ) {
m_id = id; m_expanded = expanded;
}
}
// Return map of string (group name) to info about all games in
// that group.
public static HashMap<String,GameGroupInfo> getGroups( Context context )
{
DbgUtils.logf("getGroupInfo called");
HashMap<String,GameGroupInfo> result =
new HashMap<String,GameGroupInfo>();
initDB( context );
String[] columns = { ROW_ID, DBHelper.GROUPNAME,
DBHelper.EXPANDED };
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_GROUPS, columns,
null, // selection
null, // args
null, // groupBy
null, // having
null //orderby
);
int idIndex = cursor.getColumnIndex( ROW_ID );
int nameIndex = cursor.getColumnIndex( DBHelper.GROUPNAME );
int expandedIndex = cursor.getColumnIndex( DBHelper.EXPANDED );
while ( cursor.moveToNext() ) {
String name = cursor.getString( nameIndex );
long id = cursor.getLong( idIndex );
Assert.assertNotNull( name );
DbgUtils.logf( "getGroups: got name %s, id %d", name, id );
boolean expanded = 0 != cursor.getInt( expandedIndex );
result.put( name, new GameGroupInfo( id, expanded ) );
}
cursor.close();
db.close();
}
DbgUtils.logf("getGroups=>size %d", result.size());
return result;
} // getGroups
public static long[] getGames( Context context, long groupID )
{
long[] result = null;
initDB( context );
String[] columns = { ROW_ID };
String selection = String.format( "%s=%d", DBHelper.GROUPID, groupID );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, // selection
null, // args
null, // groupBy
null, // having
ROW_ID //orderby
);
int index = cursor.getColumnIndex( ROW_ID );
result = new long[ cursor.getCount() ];
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
long rowid = cursor.getInt( index );
result[ii] = rowid;
}
cursor.close();
db.close();
}
return result;
}
public static long addGroup( Context context, String name )
{
long rowid = ROWID_NOTFOUND;
if ( null != name && 0 < name.length() ) {
HashMap<String,GameGroupInfo> gameInfo = getGroups( context );
if ( null == gameInfo.get( name ) ) {
ContentValues values = new ContentValues();
values.put( DBHelper.GROUPNAME, name );
values.put( DBHelper.EXPANDED, 0 );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
rowid = db.insert( DBHelper.TABLE_NAME_GROUPS, null,
values );
db.close();
}
}
}
return rowid;
}
public static void deleteGroup( Context context, long groupid )
{
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
// Nuke games having this group id
String selection =
String.format( "%s=%d", DBHelper.GROUPID, groupid );
db.delete( DBHelper.TABLE_NAME_SUM, selection, null );
// And nuke the group record itself
selection = String.format( ROW_ID_FMT, groupid );
db.delete( DBHelper.TABLE_NAME_GROUPS, selection, null );
db.close();
}
}
public static void setGroupName( Context context, long groupid,
String name )
{
ContentValues values = new ContentValues();
values.put( DBHelper.GROUPNAME, name );
updateRow( context, DBHelper.TABLE_NAME_GROUPS, groupid, values );
}
public static void setGroupExpanded( Context context, long groupid,
boolean expanded )
{
ContentValues values = new ContentValues();
values.put( DBHelper.EXPANDED, expanded? 1 : 0 );
updateRow( context, DBHelper.TABLE_NAME_GROUPS, groupid, values );
}
// Change group id of a game
public static void moveGame( Context context, long gameid, long groupid )
{
ContentValues values = new ContentValues();
values.put( DBHelper.GROUPID, groupid );
updateRow( context, DBHelper.TABLE_NAME_SUM, gameid, values );
}
private static void updateRow( Context context, String table,
long rowid, ContentValues values )
{
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
String selection = String.format( ROW_ID_FMT, rowid );
int result = db.update( table, values, selection, null );
db.close();
if ( 0 == result ) {
DbgUtils.logf( "updateRow failed" );
}
}
}
private static String getChatHistoryStr( Context context, long rowid )
{
String result = null;
@ -1214,6 +1352,7 @@ public class DBUtils {
private static void initDB( Context context )
{
if ( null == s_dbHelper ) {
Assert.assertNotNull( context );
s_dbHelper = new DBHelper( context );
// force any upgrade
s_dbHelper.getWritableDatabase().close();

View file

@ -27,6 +27,8 @@ import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -36,7 +38,9 @@ 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 java.util.Set;
import junit.framework.Assert;
@ -44,8 +48,9 @@ import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
public class GameListAdapter extends XWListAdapter {
public class GameListAdapter implements ExpandableListAdapter {
private Context m_context;
private LayoutInflater m_factory;
private int m_fieldID;
@ -113,7 +118,6 @@ public class GameListAdapter extends XWListAdapter {
private DateFormat m_df;
private LoadItemCB m_cb;
public interface LoadItemCB {
public void itemLoaded( long rowid );
public void itemClicked( long rowid );
@ -268,7 +272,7 @@ public class GameListAdapter extends XWListAdapter {
} // class LoadItemTask
public GameListAdapter( Context context, Handler handler, LoadItemCB cb ) {
super( DBUtils.gamesList(context).length );
// super( DBUtils.gamesList(context).length );
m_context = context;
m_handler = handler;
m_cb = cb;
@ -278,14 +282,215 @@ public class GameListAdapter extends XWListAdapter {
m_viewsCache = new HashMap<Long,ViewInfo>();
}
public void inval( long rowid )
{
synchronized( m_viewsCache ) {
m_viewsCache.remove( rowid );
}
}
public void expandGroups( ExpandableListView view )
{
HashMap<String,GameGroupInfo> info = gameInfo();
String[] names = groupNames();
for ( int ii = 0; ii < names.length; ++ii ) {
GameGroupInfo ggi = info.get( names[ii] );
if ( ggi.m_expanded ) {
view.expandGroup( ii );
}
}
}
public void setField( String field )
{
int[] ids = {
R.string.game_summary_field_empty
,R.string.game_summary_field_language
,R.string.game_summary_field_opponents
,R.string.game_summary_field_state
};
int result = -1;
for ( int id : ids ) {
if ( m_context.getString( id ).equals( field ) ) {
result = id;
break;
}
}
if ( m_fieldID != result ) {
m_viewsCache.clear();
m_fieldID = result;
}
}
public long getRowIDFor( int group, int child )
{
long rowid = DBUtils.ROWID_NOTFOUND;
String[] groupNames = groupNames();
if ( group < groupNames.length ) {
String name = groupNames()[group];
long[] rows = getRows( name );
if ( child < rows.length ) {
rowid = rows[child];
}
}
DbgUtils.logf( "getRowIDFor(%d,%d)=>%d", group, child, rowid );
return rowid;
}
public long getRowIDFor( long packedPosition )
{
int childPosition = ExpandableListView.
getPackedPositionChild( packedPosition );
int groupPosition = ExpandableListView.
getPackedPositionGroup( packedPosition );
return getRowIDFor( groupPosition, childPosition );
}
public long getGroupIDFor( int groupPos )
{
String name = groupNames()[groupPos];
GameGroupInfo ggi = gameInfo().get( name );
return ggi.m_id;
}
public String groupName( long groupid )
{
String result = null;
String[] names = groupNames();
int index;
for ( index = 0; index < names.length; ++index ) {
GameGroupInfo ggi = gameInfo().get( names[index] );
if ( groupid == ggi.m_id ) {
result = names[index];
break;
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////
// ExpandableListAdapter interface
//////////////////////////////////////////////////////////////////////////
public long getCombinedGroupId( long groupId )
{
DbgUtils.logf( "GameListAdapter.getCombinedGroupId()" );
return groupId;
}
public long getCombinedChildId( long groupId, long childId )
{
return groupId << 16 | childId;
}
public boolean isEmpty() { return false; }
public void onGroupCollapsed( int groupPosition )
{
DbgUtils.logf( "GameListAdapter.onGroupCollapsed()" );
long groupid = getGroupIDFor( groupPosition );
DBUtils.setGroupExpanded( m_context, groupid, false );
// m_closedLangs.add( m_langs[groupPosition] );
// saveClosed();
}
public void onGroupExpanded( int groupPosition )
{
DbgUtils.logf( "GameListAdapter.onGroupExpanded()" );
long groupid = getGroupIDFor( groupPosition );
DBUtils.setGroupExpanded( m_context, groupid, true );
// m_closedLangs.add( m_langs[groupPosition] );
// saveClosed();
}
public boolean areAllItemsEnabled() { return false; }
public boolean isChildSelectable( int groupPosition, int childPosition )
{ return true; }
public View getChildView( int groupPosition, int childPosition,
boolean isLastChild, View convertView,
ViewGroup parent)
{
DbgUtils.logf( "GameListAdapter.getChildView()" );
return getChildView( groupPosition, childPosition );
}
private View getChildView( int groupPosition, int childPosition )
{
DbgUtils.logf( "GameListAdapter.getChildView()" );
// String name = m_groupNames[groupPosition];
// long[] games = DBUtils.getGames( m_context, m_gameInfo.get(name).m_id );
long rowid = getRowIDFor( groupPosition, childPosition );
return getItem( rowid );
}
public View getGroupView( int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent )
{
DbgUtils.logf( "GameListAdapter.getGroupView()" );
View row =
Utils.inflate(m_context,
android.R.layout.simple_expandable_list_item_1 );
TextView view = (TextView)row.findViewById( android.R.id.text1 );
String name = groupNames()[groupPosition];
if ( name.equals("") ) {
name = "<Unnamed>";
}
if ( !isExpanded ) {
name += " (%d/%d)";
}
view.setText( name );
return view;
}
public boolean hasStableIds() { return false; }
public int getCount() {
return DBUtils.gamesList(m_context).length;
public long getChildId( int groupPosition, int childPosition )
{
DbgUtils.logf( "GameListAdapter.getChildId()" );
return childPosition;
}
public long getGroupId( int groupPosition )
{
DbgUtils.logf( "GameListAdapter.getGroupId()" );
return groupPosition;
}
public Object getChild( int groupPosition, int childPosition )
{
DbgUtils.logf( "GameListAdapter.getChild()" );
String name = groupNames()[groupPosition];
long[] rows = getRows( name );
return rows[childPosition];
}
public Object getItem( int position )
public Object getGroup( int groupPosition )
{
final long rowid = DBUtils.gamesList(m_context)[position];
DbgUtils.logf("GameListAdapter.getGroup()");
return null;
}
public int getChildrenCount( int groupPosition )
{
DbgUtils.logf("GameListAdapter.getChildrenCount()");
String name = groupNames()[ groupPosition ];
long[] rows = getRows( name );
return rows.length;
}
public int getGroupCount()
{
// DbgUtils.logf("GameListAdapter.getGroupCount()");
return groupNames().length;
}
public void registerDataSetObserver( DataSetObserver obs ){}
public void unregisterDataSetObserver( DataSetObserver obs ){}
private View getItem( final long rowid )
{
DbgUtils.logf("GameListAdapter.getItem()");
View layout;
boolean haveLayout = false;
synchronized( m_viewsCache ) {
@ -318,36 +523,26 @@ public class GameListAdapter extends XWListAdapter {
return layout;
} // getItem
public View getView( int position, View convertView, ViewGroup parent ) {
return (View)getItem( position );
private long[] getRows( String group )
{
GameGroupInfo ggi = gameInfo().get(group);
long groupID = ggi.m_id;
long[] rows = DBUtils.getGames( m_context, groupID );
return rows;
}
public void inval( long rowid )
public String[] groupNames()
{
synchronized( m_viewsCache ) {
m_viewsCache.remove( rowid );
}
HashMap<String,GameGroupInfo> info = gameInfo();
Set<String> set = info.keySet();
String[] names = new String[ set.size() ];
set.toArray(names);
return names;
}
public void setField( String field )
private HashMap<String,GameGroupInfo> gameInfo()
{
int[] ids = {
R.string.game_summary_field_empty
,R.string.game_summary_field_language
,R.string.game_summary_field_opponents
,R.string.game_summary_field_state
};
int result = -1;
for ( int id : ids ) {
if ( m_context.getString( id ).equals( field ) ) {
result = id;
break;
}
}
if ( m_fieldID != result ) {
m_viewsCache.clear();
m_fieldID = result;
}
return DBUtils.getGroups( m_context );
}
}

View file

@ -20,37 +20,39 @@
package org.eehouse.android.xw4;
import android.app.ListActivity;
import android.app.Dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Button;
import android.view.MenuInflater;
import java.io.File;
import android.preference.PreferenceManager;
// import android.telephony.PhoneStateListener;
// import android.telephony.TelephonyManager;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
public class GamesList extends XWListActivity
public class GamesList extends XWExpandableListActivity
implements DispatchNotify.HandleRelaysIface,
DBUtils.DBChangeListener,
GameListAdapter.LoadItemCB,
@ -61,8 +63,12 @@ public class GamesList extends XWListActivity
private static final int SHOW_SUBST = WARN_NODICT + 2;
private static final int GET_NAME = WARN_NODICT + 3;
private static final int RENAME_GAME = WARN_NODICT + 4;
private static final int NEW_GROUP = WARN_NODICT + 5;
private static final int RENAME_GROUP = WARN_NODICT + 6;
private static final int CHANGE_GROUP = WARN_NODICT + 7;
private static final String SAVE_ROWID = "SAVE_ROWID";
private static final String SAVE_GROUPID = "SAVE_GROUPID";
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
private static final int NEW_NET_GAME_ACTION = 1;
@ -71,6 +77,7 @@ public class GamesList extends XWListActivity
private static final int DELETE_ALL_ACTION = 4;
private static final int SYNC_MENU_ACTION = 5;
private static final int NEW_FROM_ACTION = 6;
private static final int DELETE_GROUP_ACTION = 7;
private static final int[] DEBUGITEMS = { R.id.gamel_menu_loaddb
, R.id.gamel_menu_storedb
, R.id.gamel_menu_checkupdates
@ -85,14 +92,17 @@ public class GamesList extends XWListActivity
private String[] m_sameLangDicts;
private int m_missingDictLang;
private long m_rowid;
private long m_groupid;
private String m_nameField;
private NetLaunchInfo m_netLaunchInfo;
private GameNamer m_namer;
// private String m_smsPhone;
@Override
protected Dialog onCreateDialog( int id )
{
DialogInterface.OnClickListener lstnr;
DialogInterface.OnClickListener lstnr2;
LinearLayout layout;
Dialog dialog = super.onCreateDialog( id );
@ -162,37 +172,80 @@ public class GamesList extends XWListActivity
.setNegativeButton( R.string.button_cancel, null )
.setSingleChoiceItems( m_sameLangDicts, 0, null )
.create();
;
// Force destruction so onCreateDialog() will get
// called next time and we can insert a different
// list. There seems to be no way to change the list
// inside onPrepareDialog().
dialog.setOnDismissListener(new DialogInterface.
OnDismissListener() {
public void onDismiss(DialogInterface dlg) {
removeDialog( SHOW_SUBST );
}
});
Utils.setRemoveOnDismiss( this, dialog, id );
break;
case RENAME_GAME:
final GameNamer namerView =
(GameNamer)Utils.inflate( this, R.layout.rename_game );
namerView.setName( GameUtils.getName( this, m_rowid ) );
namerView.setLabel( R.string.rename_label );
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = namerView.getName();
String name = m_namer.getName();
DBUtils.setName( GamesList.this, m_rowid, name );
m_adapter.inval( m_rowid );
onContentChanged();
}
};
dialog = buildNamerDlg( GameUtils.getName( this, m_rowid ),
R.string.rename_label,
R.string.game_rename_title,
lstnr, RENAME_GAME );
break;
case RENAME_GROUP:
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = m_namer.getName();
DBUtils.setGroupName( GamesList.this, m_groupid,
name );
m_adapter.inval( m_rowid );
onContentChanged();
}
};
dialog = buildNamerDlg( m_adapter.groupName( m_groupid ),
R.string.rename_group_label,
R.string.game_rename_group_title,
lstnr, RENAME_GROUP );
break;
case NEW_GROUP:
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = m_namer.getName();
DBUtils.addGroup( GamesList.this, name );
// m_adapter.inval();
onContentChanged();
}
};
dialog = buildNamerDlg( "", R.string.newgroup_label,
R.string.game_rename_title,
lstnr, RENAME_GROUP );
break;
case CHANGE_GROUP:
final int[] selItem = {-1}; // hack!!!!
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
selItem[0] = item;
}
};
lstnr2 = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
if ( -1 != selItem[0] ) {
long groupid =
m_adapter.getGroupIDFor( selItem[0] );
DBUtils.moveGame( GamesList.this, m_rowid,
groupid );
onContentChanged();
}
}
};
String[] groups = m_adapter.groupNames();
dialog = new AlertDialog.Builder( this )
.setTitle( R.string.game_rename_title )
.setNegativeButton( R.string.button_cancel, null )
.setPositiveButton( R.string.button_ok, lstnr )
.setView( namerView )
.setSingleChoiceItems( groups, -1, lstnr )
.setPositiveButton( R.string.button_ok, lstnr2 )
.create();
Utils.setRemoveOnDismiss( this, dialog, id );
break;
@ -243,7 +296,7 @@ public class GamesList extends XWListActivity
getBundledData( savedInstanceState );
setContentView(R.layout.game_list);
registerForContextMenu( getListView() );
registerForContextMenu( getExpandableListView() );
DBUtils.setDBChangeListener( this );
boolean isUpgrade = Utils.firstBootThisVersion( this );
@ -265,6 +318,13 @@ public class GamesList extends XWListActivity
// R.string.key_notagain_newgame );
}
});
newGameB = (Button)findViewById(R.id.new_group);
newGameB.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
showDialog( NEW_GROUP );
}
});
m_adapter = new GameListAdapter( this, new Handler(), this );
setListAdapter( m_adapter );
@ -301,13 +361,13 @@ public class GamesList extends XWListActivity
boolean hide = CommonPrefs.getHideIntro( this );
int hereOrGone = hide ? View.GONE : View.VISIBLE;
for ( int id : new int[]{ R.id.empty_games_list,
R.id.new_game } ) {
R.id.new_buttons } ) {
View view = findViewById( id );
view.setVisibility( hereOrGone );
}
View empty = findViewById( R.id.empty_list_msg );
empty.setVisibility( hide ? View.VISIBLE : View.GONE );
getListView().setEmptyView( hide? empty : null );
getExpandableListView().setEmptyView( hide? empty : null );
// TelephonyManager mgr =
// (TelephonyManager)getSystemService( Context.TELEPHONY_SERVICE );
@ -316,6 +376,13 @@ public class GamesList extends XWListActivity
// PhoneStateListener.LISTEN_DATA_CONNECTION_STATE );
}
@Override
protected void onResume()
{
super.onResume();
m_adapter.expandGroups( getExpandableListView() );
}
@Override
protected void onStop()
{
@ -340,6 +407,7 @@ public class GamesList extends XWListActivity
{
super.onSaveInstanceState( outState );
outState.putLong( SAVE_ROWID, m_rowid );
outState.putLong( SAVE_GROUPID, m_groupid );
outState.putStringArray( SAVE_DICTNAMES, m_missingDictNames );
if ( null != m_netLaunchInfo ) {
m_netLaunchInfo.putSelf( outState );
@ -350,6 +418,7 @@ public class GamesList extends XWListActivity
{
if ( null != bundle ) {
m_rowid = bundle.getLong( SAVE_ROWID );
m_groupid = bundle.getLong( SAVE_GROUPID );
m_netLaunchInfo = new NetLaunchInfo( bundle );
m_missingDictNames = bundle.getStringArray( SAVE_DICTNAMES );
}
@ -491,6 +560,10 @@ public class GamesList extends XWListActivity
m_adapter.inval( newid );
}
break;
case DELETE_GROUP_ACTION:
DBUtils.deleteGroup( this, m_groupid );
break;
default:
Assert.fail();
}
@ -501,30 +574,48 @@ public class GamesList extends XWListActivity
public void onCreateContextMenu( ContextMenu menu, View view,
ContextMenuInfo menuInfo )
{
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.games_list_item_menu, menu );
ExpandableListView.ExpandableListContextMenuInfo info
= (ExpandableListView.ExpandableListContextMenuInfo)menuInfo;
long packedPos = info.packedPosition;
int childPos = ExpandableListView.getPackedPositionChild( packedPos );
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo)menuInfo;
int position = info.position;
long rowid = DBUtils.gamesList( this )[position];
String title = GameUtils.getName( this, rowid );
menu.setHeaderTitle( getString( R.string.game_item_menu_titlef,
title ) );
if ( 0 <= childPos ) {
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.games_list_item_menu, menu );
long rowid = m_adapter.getRowIDFor( packedPos );
String title = GameUtils.getName( this, rowid );
menu.setHeaderTitle( getString( R.string.game_item_menu_titlef,
title ) );
} else {
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.games_list_group_menu, menu );
}
}
@Override
public boolean onContextItemSelected( MenuItem item )
{
AdapterView.AdapterContextMenuInfo info;
ExpandableListContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
info = (ExpandableListContextMenuInfo)item.getMenuInfo();
} catch (ClassCastException cce) {
DbgUtils.loge( cce );
return false;
}
return handleMenuItem( item.getItemId(), info.position );
long packedPos = info.packedPosition;
int childPos = ExpandableListView.getPackedPositionChild( packedPos );
int groupPos = ExpandableListView.getPackedPositionGroup(packedPos);
int menuID = item.getItemId();
boolean handled;
if ( 0 <= childPos ) {
long rowid = m_adapter.getRowIDFor( groupPos, childPos );
handled = handleGameMenuItem( menuID, rowid );
} else {
handled = handleGroupMenuItem( menuID, groupPos );
}
return handled;
} // onContextItemSelected
@Override
@ -628,12 +719,12 @@ public class GamesList extends XWListActivity
} );
}
private boolean handleMenuItem( int menuID, int position )
private boolean handleGameMenuItem( int menuID, long rowid )
{
boolean handled = true;
DialogInterface.OnClickListener lstnr;
m_rowid = DBUtils.gamesList( this )[position];
m_rowid = rowid;
if ( R.id.list_item_delete == menuID ) {
showConfirmThen( R.string.confirm_delete, R.string.button_delete,
@ -651,7 +742,9 @@ public class GamesList extends XWListActivity
case R.id.list_item_rename:
showDialog( RENAME_GAME );
break;
case R.id.list_item_move:
showDialog( CHANGE_GROUP );
break;
case R.id.list_item_new_from:
showNotAgainDlgThen( R.string.not_again_newfrom,
R.string.key_notagain_newfrom,
@ -688,7 +781,32 @@ public class GamesList extends XWListActivity
}
return handled;
} // handleMenuItem
} // handleGameMenuItem
private boolean handleGroupMenuItem( int menuID, int groupPos )
{
boolean handled = true;
m_groupid = m_adapter.getGroupIDFor( groupPos );
switch ( menuID ) {
case R.id.list_group_delete:
String msg = getString( R.string.group_confirm_del );
int nGames = m_adapter.getChildrenCount( groupPos );
if ( 0 < nGames ) {
msg += getString( R.string.group_confirm_delf, nGames );
}
showConfirmThen( msg, DELETE_GROUP_ACTION );
break;
case R.id.list_group_rename:
showDialog( RENAME_GROUP );
break;
case R.id.list_group_default:
XWPrefs.setDefaultNewGameGroup( this, m_groupid );
break;
default:
handled = false;
}
return handled;
}
private boolean checkWarnNoDict( long rowid )
{
@ -818,4 +936,22 @@ public class GamesList extends XWListActivity
onContentChanged();
}
}
private Dialog buildNamerDlg( String curname, int labelID, int titleID,
DialogInterface.OnClickListener lstnr,
int dlgID )
{
m_namer = (GameNamer)Utils.inflate( this, R.layout.rename_game );
m_namer.setName( curname );
m_namer.setLabel( labelID );
Dialog dialog = new AlertDialog.Builder( this )
.setTitle( titleID )
.setNegativeButton( R.string.button_cancel, null )
.setPositiveButton( R.string.button_ok, lstnr )
.setView( m_namer )
.create();
Utils.setRemoveOnDismiss( this, dialog, dlgID );
return dialog;
}
}

View file

@ -32,7 +32,7 @@ public class XWApp extends Application {
public static final boolean BTSUPPORTED = false;
public static final boolean SMSSUPPORTED = true;
public static final boolean GCMSUPPORTED = true;
public static final boolean DEBUG = false;
public static final boolean DEBUG = true;
public static final String SMS_PUBLIC_HEADER = "-XW4";

View file

@ -0,0 +1,140 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 - 2011 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.app.Dialog;
import android.app.ExpandableListActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import junit.framework.Assert;
public class XWExpandableListActivity extends ExpandableListActivity
implements DlgDelegate.DlgClickNotify, MultiService.BTEventListener {
private DlgDelegate m_delegate;
@Override
protected void onCreate( Bundle savedInstanceState )
{
DbgUtils.logf( "%s.onCreate(this=%H)", getClass().getName(), this );
super.onCreate( savedInstanceState );
m_delegate = new DlgDelegate( this, this, savedInstanceState );
}
@Override
protected void onSaveInstanceState( Bundle outState )
{
super.onSaveInstanceState( outState );
m_delegate.onSaveInstanceState( outState );
}
@Override
protected Dialog onCreateDialog( final int id )
{
DbgUtils.logf( "%s.onCreateDialog() called", getClass().getName() );
Dialog dialog = m_delegate.onCreateDialog( id );
if ( null == dialog ) {
dialog = super.onCreateDialog( id );
}
return dialog;
}
@Override
protected void onPrepareDialog( int id, Dialog dialog )
{
super.onPrepareDialog( id, dialog );
m_delegate.onPrepareDialog( id, dialog );
}
protected boolean post( Runnable runnable )
{
return m_delegate.post( runnable );
}
protected void doSyncMenuitem()
{
m_delegate.doSyncMenuitem();
}
protected void showNotAgainDlgThen( int msgID, int prefsKey,
int action )
{
m_delegate.showNotAgainDlgThen( msgID, prefsKey, action );
}
protected void showNotAgainDlg( int msgID, int prefsKey )
{
m_delegate.showNotAgainDlgThen( msgID, prefsKey );
}
// It sucks that these must be duplicated here and XWActivity
protected void showAboutDialog()
{
m_delegate.showAboutDialog();
}
protected void showOKOnlyDialog( int msgID )
{
m_delegate.showOKOnlyDialog( msgID );
}
protected void showConfirmThen( String msg, int action )
{
m_delegate.showConfirmThen( msg, action );
}
protected void showConfirmThen( int msg, int action )
{
showConfirmThen( getString(msg), action );
}
protected void showConfirmThen( String msg, int posButton, int action )
{
m_delegate.showConfirmThen( msg, posButton, action );
}
protected void showConfirmThen( int msg, int posButton, int action )
{
m_delegate.showConfirmThen( getString(msg), posButton, action );
}
// protected void showConfirmThen( String msg, int action )
// {
// m_delegate.showConfirmThen( msg, action );
// }
// DlgDelegate.DlgClickNotify interface
public void dlgButtonClicked( int id, int which )
{
Assert.fail();
}
// BTService.BTEventListener interface
public void eventOccurred( MultiService.MultiEvent event,
final Object ... args )
{
m_delegate.eventOccurred( event, args );
}
}

View file

@ -107,12 +107,6 @@ public class XWListActivity extends ListActivity
m_delegate.onPrepareDialog( id, dialog );
}
// It sucks that these must be duplicated here and XWActivity
protected void showAboutDialog()
{
m_delegate.showAboutDialog();
}
protected void showNotAgainDlgThen( int msgID, int prefsKey,
int action )
{

View file

@ -151,6 +151,25 @@ public class XWPrefs {
editor.commit();
}
public static long getPrefsLong( Context context, int keyID,
long defaultValue )
{
String key = context.getString( keyID );
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences( context );
return sp.getLong( key, defaultValue );
}
public static void setPrefsLong( Context context, int keyID, long newVal )
{
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences( context );
SharedPreferences.Editor editor = sp.edit();
String key = context.getString( keyID );
editor.putLong( key, newVal );
editor.commit();
}
public static void setClosedLangs( Context context, String[] langs )
{
setPrefsString( context, R.string.key_closed_langs,
@ -275,6 +294,17 @@ public class XWPrefs {
return getPrefsBoolean( context, R.string.key_default_loc, true );
}
public static long getDefaultNewGameGroup( Context context )
{
return getPrefsLong( context, R.string.key_default_group,
DBUtils.ROWID_NOTFOUND );
}
public static void setDefaultNewGameGroup( Context context, long val )
{
setPrefsLong( context, R.string.key_default_group, val );
}
protected static String getPrefsString( Context context, int keyID )
{
String key = context.getString( keyID );