From 0b0a50bd5c08c1a704ca9af8626e1102a57f5e1c Mon Sep 17 00:00:00 2001 From: Eric House Date: Thu, 8 Jun 2017 13:04:59 -0700 Subject: [PATCH] add timestamp to chat messages, db and display On send, add current seconds to message. Store and display in android code. Display layout needs work. --- .../eehouse/android/xw4/BoardDelegate.java | 6 ++--- .../org/eehouse/android/xw4/ChatDelegate.java | 26 ++++++++++++++----- .../org/eehouse/android/xw4/DBHelper.java | 24 +++++++++++++---- .../java/org/eehouse/android/xw4/DBUtils.java | 22 ++++++++++------ .../org/eehouse/android/xw4/GameUtils.java | 8 ++++-- .../org/eehouse/android/xw4/jni/UtilCtxt.java | 2 +- .../eehouse/android/xw4/jni/UtilCtxtImpl.java | 2 +- .../app/src/main/res/layout/chat_row.xml | 7 +++++ xwords4/android/jni/utilwrapper.c | 6 ++--- xwords4/common/server.c | 21 +++++++++------ xwords4/common/util.h | 4 +-- xwords4/linux/cursesmain.c | 2 +- xwords4/linux/gtkboard.c | 5 ++-- 13 files changed, 92 insertions(+), 43 deletions(-) diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java index 9bcec8427..32ed2e816 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java @@ -1997,14 +1997,14 @@ public class BoardDelegate extends DelegateBase // chat-messages. @Override public void showChat( final String msg, final int fromIndx, - String fromPlayer ) + String fromPlayer, final int tsSeconds ) { runOnUiThread( new Runnable() { public void run() { DBUtils.appendChatHistory( m_activity, m_rowid, msg, - fromIndx ); + fromIndx, tsSeconds ); if ( ! ChatDelegate.append( m_rowid, msg, - fromIndx ) ) { + fromIndx, tsSeconds ) ) { startChatActivity(); } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ChatDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ChatDelegate.java index d8e401ce8..54eb045a1 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ChatDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ChatDelegate.java @@ -28,8 +28,8 @@ import android.text.Editable; import android.text.TextWatcher; import android.view.Menu; import android.view.MenuItem; -import android.view.View; import android.view.View.OnLayoutChangeListener; +import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ScrollView; @@ -37,6 +37,9 @@ import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; +import java.text.DateFormat; +import java.util.Date; + import junit.framework.Assert; import org.eehouse.android.xw4.DlgDelegate.Action; @@ -115,7 +118,7 @@ public class ChatDelegate extends DelegateBase { = DBUtils.getChatHistory( m_activity, m_rowid, locals ); if ( null != pairs ) { for ( DBUtils.HistoryPair pair : pairs ) { - addRow( pair.msg, pair.playerIndx ); + addRow( pair.msg, pair.playerIndx, pair.ts ); } } @@ -160,7 +163,7 @@ public class ChatDelegate extends DelegateBase { super.onPause(); } - private void addRow( String msg, int playerIndx ) + private void addRow( String msg, int playerIndx, long tsSeconds ) { TableRow row = (TableRow)inflate( R.layout.chat_row ); if ( m_curPlayer == playerIndx ) { @@ -171,6 +174,14 @@ public class ChatDelegate extends DelegateBase { view = (TextView)row.findViewById( R.id.chat_row_name ); view.setText( getString( R.string.chat_sender_fmt, m_names[playerIndx] ) ); + + if ( tsSeconds > 0 ) { + view = (TextView)row.findViewById( R.id.chat_row_time ); + DateFormat df = DateFormat.getDateTimeInstance( DateFormat.SHORT, + DateFormat.SHORT ); + view.setText( df.format( new Date( 1000L * tsSeconds ) ) ); + } + m_layout.addView( row ); scrollDown(); @@ -188,8 +199,9 @@ public class ChatDelegate extends DelegateBase { private void handleSend() { String text = m_edit.getText().toString(); - DBUtils.appendChatHistory( m_activity, m_rowid, text, m_curPlayer ); - addRow( text, m_curPlayer ); + long ts = Utils.getCurSeconds(); + DBUtils.appendChatHistory( m_activity, m_rowid, text, m_curPlayer, ts ); + addRow( text, m_curPlayer, (int)ts ); m_edit.setText( null ); m_jniThreadRef.sendChat( text ); @@ -241,12 +253,12 @@ public class ChatDelegate extends DelegateBase { return handled; } - public static boolean append( long rowid, String msg, int fromIndx ) + public static boolean append( long rowid, String msg, int fromIndx, long tsSeconds ) { boolean handled = null != s_visibleThis && s_visibleThis.m_rowid == rowid; if ( handled ) { - s_visibleThis.addRow( msg, fromIndx ); + s_visibleThis.addRow( msg, fromIndx, tsSeconds ); Utils.playNotificationSound( s_visibleThis.m_activity ); } return handled; diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBHelper.java index 322f9cbc9..2ad778b82 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBHelper.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBHelper.java @@ -47,7 +47,7 @@ public class DBHelper extends SQLiteOpenHelper { public static final String TABLE_NAME_CHAT = "chat"; public static final String TABLE_NAME_LOGS = "logs"; private static final String DB_NAME = "xwdb"; - private static final int DB_VERSION = 28; + private static final int DB_VERSION = 29; public static final String GAME_NAME = "GAME_NAME"; public static final String VISID = "VISID"; @@ -98,6 +98,7 @@ public class DBHelper extends SQLiteOpenHelper { public static final String ITERPREFIX = "ITERPREFIX"; public static final String CREATE_TIME = "CREATE_TIME"; public static final String LASTPLAY_TIME = "LASTPLAY_TIME"; + public static final String CHATTIME = "CHATTIME"; public static final String GROUPNAME = "GROUPNAME"; public static final String EXPANDED = "EXPANDED"; @@ -221,6 +222,7 @@ public class DBHelper extends SQLiteOpenHelper { { ROW, "INTEGER" } ,{ SENDER, "INTEGER" } ,{ MESSAGE, "TEXT" } + ,{ CHATTIME, "INTEGER DEFAULT 0" } }; private static final String[][] s_logsSchema = { @@ -264,6 +266,7 @@ public class DBHelper extends SQLiteOpenHelper { Log.i( TAG, "onUpgrade: old: %d; new: %d", oldVersion, newVersion ); boolean madeSumTable = false; + boolean madeChatTable = false; switch( oldVersion ) { case 5: createTable( db, TABLE_NAME_OBITS, s_obitsColsAndTypes ); @@ -324,12 +327,17 @@ public class DBHelper extends SQLiteOpenHelper { createInvitesTable( db ); case 25: createChatsTable( db ); + madeChatTable = true; case 26: createLogsTable( db ); case 27: if ( !madeSumTable ) { addSumColumn( db, TURN_LOCAL ); } + case 28: + if ( !madeChatTable ) { + addColumn( db, TABLE_NAME_CHAT, s_chatsSchema, CHATTIME ); + } break; default: @@ -354,17 +362,23 @@ public class DBHelper extends SQLiteOpenHelper { } private void addSumColumn( SQLiteDatabase db, String colName ) + { + addColumn( db, TABLE_NAME_SUM, s_summaryColsAndTypes, colName ); + } + + private void addColumn( SQLiteDatabase db, String tableName, + String[][] colsAndTypes, String colName ) { String colType = null; - for ( int ii = 0; ii < s_summaryColsAndTypes.length; ++ii ) { - if ( s_summaryColsAndTypes[ii][0].equals( colName ) ) { - colType = s_summaryColsAndTypes[ii][1]; + for ( int ii = 0; ii < colsAndTypes.length; ++ii ) { + if ( colsAndTypes[ii][0].equals( colName ) ) { + colType = colsAndTypes[ii][1]; break; } } String cmd = String.format( "ALTER TABLE %s ADD COLUMN %s %s;", - TABLE_NAME_SUM, colName, colType ); + tableName, colName, colType ); db.execSQL( cmd ); } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java index 997329f24..7c177e2b4 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java @@ -106,13 +106,15 @@ public class DBUtils { } public static class HistoryPair { - private HistoryPair( String p_msg, int p_playerIndx ) + private HistoryPair( String p_msg, int p_playerIndx, int p_ts ) { msg = p_msg; playerIndx = p_playerIndx; + ts = p_ts; } String msg; int playerIndx; + int ts; } public static class DictBrowseState { @@ -1217,9 +1219,9 @@ public class DBUtils { Log.d( TAG, "convertChatString(): removing substring %s; was: %s", prefix, msg ); msg = msg.substring( prefix.length(), msg.length() ); Log.d( TAG, "convertChatString(): removED substring; now %s", msg ); - valuess.add( cvForChat( rowid, msg, indx ) ); + valuess.add( cvForChat( rowid, msg, indx, 0 ) ); - HistoryPair pair = new HistoryPair(msg, indx ); + HistoryPair pair = new HistoryPair( msg, indx, 0 ); pairs.add( pair ); } } @@ -1235,7 +1237,7 @@ public class DBUtils { boolean[] playersLocal ) { HistoryPair[] result = null; - String[] columns = { DBHelper.SENDER, DBHelper.MESSAGE }; + String[] columns = { DBHelper.SENDER, DBHelper.MESSAGE, DBHelper.CHATTIME }; String selection = String.format( "%s=%d", DBHelper.ROW, rowid ); initDB( context ); synchronized( s_dbHelper ) { @@ -1245,10 +1247,12 @@ public class DBUtils { result = new HistoryPair[cursor.getCount()]; int msgIndex = cursor.getColumnIndex( DBHelper.MESSAGE ); int plyrIndex = cursor.getColumnIndex( DBHelper.SENDER ); + int tsIndex = cursor.getColumnIndex( DBHelper.CHATTIME ); for ( int ii = 0; cursor.moveToNext(); ++ii ) { String msg = cursor.getString( msgIndex ); int plyr = cursor.getInt( plyrIndex ); - HistoryPair pair = new HistoryPair(msg, plyr ); + int ts = cursor.getInt( tsIndex ); + HistoryPair pair = new HistoryPair( msg, plyr, ts ); result[ii] = pair; } } @@ -1766,22 +1770,24 @@ public class DBUtils { } } - private static ContentValues cvForChat( long rowid, String msg, int plyr ) + private static ContentValues cvForChat( long rowid, String msg, int plyr, long tsSeconds ) { ContentValues values = new ContentValues(); values.put( DBHelper.ROW, rowid ); values.put( DBHelper.MESSAGE, msg ); values.put( DBHelper.SENDER, plyr ); + values.put( DBHelper.CHATTIME, tsSeconds ); return values; } public static void appendChatHistory( Context context, long rowid, - String msg, int fromPlayer ) + String msg, int fromPlayer, + long tsSeconds ) { Assert.assertNotNull( msg ); Assert.assertFalse( -1 == fromPlayer ); ArrayList valuess = new ArrayList(); - valuess.add( cvForChat( rowid, msg, fromPlayer ) ); + valuess.add( cvForChat( rowid, msg, fromPlayer, tsSeconds ) ); appendChatHistory( context, valuess ); Log.i( TAG, "appendChatHistory: inserted \"%s\" from player %d", msg, fromPlayer ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java index a3c246053..39d0be250 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java @@ -82,6 +82,7 @@ public class GameUtils { LastMoveInfo m_lmi; // instantiated on demand String m_chat; String m_chatFrom; + long m_chatTs; } private static Object s_syncObj = new Object(); @@ -866,6 +867,7 @@ public class GameUtils { private Context m_context; private long m_rowid; public String m_chat; + public long m_ts; public boolean m_gotMsg; public boolean m_gotChat; public String m_chatFrom; @@ -880,12 +882,13 @@ public class GameUtils { m_gameOver = false; } @Override - public void showChat( String msg, int fromIndx, String fromName ) + public void showChat( String msg, int fromIndx, String fromName, int tsSeconds ) { - DBUtils.appendChatHistory( m_context, m_rowid, msg, fromIndx ); + DBUtils.appendChatHistory( m_context, m_rowid, msg, fromIndx, tsSeconds ); m_gotChat = true; m_chatFrom = fromName; m_chat = msg; + m_ts = tsSeconds; } public void turnChanged( int newTurn ) { @@ -935,6 +938,7 @@ public class GameUtils { if ( null != feedImpl.m_chat ) { bmr.m_chat = feedImpl.m_chat; bmr.m_chatFrom = feedImpl.m_chatFrom; + bmr.m_chatTs = feedImpl.m_ts; } else { LastMoveInfo lmi = new LastMoveInfo(); XwJNI.model_getPlayersLastScore( gamePtr, -1, lmi ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java index 082398167..cc34891be 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java @@ -145,7 +145,7 @@ public interface UtilCtxt { void notifyIllegalWords( String dict, String[] words, int turn, boolean turnLost ); - void showChat( String msg, int fromIndx, String fromName ); + void showChat( String msg, int fromIndx, String fromName, int tsSeconds ); boolean phoneNumbersSame( String num1, String num2 ); } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java index 97361f178..d18821342 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java @@ -288,7 +288,7 @@ public class UtilCtxtImpl implements UtilCtxt { } // These need to go into some sort of chat DB, not dropped. - public void showChat( String msg, int fromIndx, String fromName ) + public void showChat( String msg, int fromIndx, String fromName, int tsSeconds ) { subclassOverride( "showChat" ); } diff --git a/xwords4/android/app/src/main/res/layout/chat_row.xml b/xwords4/android/app/src/main/res/layout/chat_row.xml index 57609ade8..184175123 100644 --- a/xwords4/android/app/src/main/res/layout/chat_row.xml +++ b/xwords4/android/app/src/main/res/layout/chat_row.xml @@ -13,4 +13,11 @@ android:layout_width="0dp" android:layout_weight="1" /> + diff --git a/xwords4/android/jni/utilwrapper.c b/xwords4/android/jni/utilwrapper.c index 558412fdc..fb6aa18f5 100644 --- a/xwords4/android/jni/utilwrapper.c +++ b/xwords4/android/jni/utilwrapper.c @@ -474,9 +474,9 @@ and_util_notifyIllegalWords( XW_UtilCtxt* uc, BadWordInfo* bwi, #ifdef XWFEATURE_CHAT static void -and_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* msg, XP_S16 from ) +and_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* msg, XP_S16 from, XP_U32 timestamp ) { - UTIL_CBK_HEADER( "showChat", "(Ljava/lang/String;ILjava/lang/String;)V" ); + UTIL_CBK_HEADER( "showChat", "(Ljava/lang/String;ILjava/lang/String;I)V" ); jstring jname = NULL; if ( 0 <= from ) { LocalPlayer* lp = &uc->gameInfo->players[from]; @@ -485,7 +485,7 @@ and_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* msg, XP_S16 from ) } jstring jmsg = (*env)->NewStringUTF( env, msg ); - (*env)->CallVoidMethod( env, util->jutil, mid, jmsg, from, jname ); + (*env)->CallVoidMethod( env, util->jutil, mid, jmsg, from, jname, timestamp ); deleteLocalRefs( env, jmsg, jname, DELETE_NO_REF ); UTIL_CBK_TAIL(); } diff --git a/xwords4/common/server.c b/xwords4/common/server.c index 06929ccfa..835278ea5 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -643,13 +643,14 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream ) #ifdef XWFEATURE_CHAT static void sendChatTo( ServerCtxt* server, XP_U16 devIndex, const XP_UCHAR* msg, - XP_S8 from ) + XP_S8 from, XP_U32 timestamp ) { if ( comms_canChat( server->vol.comms ) ) { XWStreamCtxt* stream = messageStreamWithHeader( server, devIndex, XWPROTO_CHAT ); stringToStream( stream, msg ); stream_putU8( stream, from ); + stream_putU32( stream, timestamp ); stream_destroy( stream ); } else { XP_LOGF( "%s: dropping chat %s; queue too full?", __func__, msg ); @@ -657,13 +658,13 @@ sendChatTo( ServerCtxt* server, XP_U16 devIndex, const XP_UCHAR* msg, } static void -sendChatToClientsExcept( ServerCtxt* server, XP_U16 skip, - const XP_UCHAR* msg, XP_S8 from ) +sendChatToClientsExcept( ServerCtxt* server, XP_U16 skip, const XP_UCHAR* msg, + XP_S8 from, XP_U32 timestamp ) { XP_U16 devIndex; for ( devIndex = 1; devIndex < server->nv.nDevices; ++devIndex ) { if ( devIndex != skip ) { - sendChatTo( server, devIndex, msg, from ); + sendChatTo( server, devIndex, msg, from, timestamp ); } } } @@ -671,10 +672,11 @@ sendChatToClientsExcept( ServerCtxt* server, XP_U16 skip, void server_sendChat( ServerCtxt* server, const XP_UCHAR* msg, XP_S16 from ) { + XP_U32 timestamp = util_getCurSeconds( server->vol.util ); if ( server->vol.gi->serverRole == SERVER_ISCLIENT ) { - sendChatTo( server, SERVER_DEVICE, msg, from ); + sendChatTo( server, SERVER_DEVICE, msg, from, timestamp ); } else { - sendChatToClientsExcept( server, SERVER_DEVICE, msg, from ); + sendChatToClientsExcept( server, SERVER_DEVICE, msg, from, timestamp ); } } #endif @@ -2927,12 +2929,15 @@ server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming ) XP_UCHAR* msg = stringFromStream( server->mpool, incoming ); XP_S16 from = 1 <= stream_getSize( incoming ) ? stream_getU8( incoming ) : -1; + XP_U32 timestamp = sizeof(timestamp) <= stream_getSize( incoming ) + ? stream_getU32( incoming ) : 0; if ( isServer ) { XP_U16 sourceClientIndex = getIndexForDevice( server, stream_getAddress( incoming ) ); - sendChatToClientsExcept( server, sourceClientIndex, msg, from ); + sendChatToClientsExcept( server, sourceClientIndex, msg, from, + timestamp ); } - util_showChat( server->vol.util, msg, from ); + util_showChat( server->vol.util, msg, from, timestamp ); XP_FREE( server->mpool, msg ); #endif } else if ( readStreamHeader( server, incoming ) ) { diff --git a/xwords4/common/util.h b/xwords4/common/util.h index ea4888d79..85a726df8 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -193,7 +193,7 @@ typedef struct UtilVtable { #ifdef XWFEATURE_CHAT void (*m_util_showChat)( XW_UtilCtxt* uc, const XP_UCHAR* const msg, - XP_S16 from ); + XP_S16 from, XP_U32 timestamp ); #endif #ifdef SHOW_PROGRESS @@ -342,7 +342,7 @@ struct XW_UtilCtxt { #endif #ifdef XWFEATURE_CHAT -# define util_showChat( uc, m, f ) (uc)->vtable->m_util_showChat((uc),(m),(f)) +# define util_showChat( uc, m, f, ts ) (uc)->vtable->m_util_showChat((uc),(m),(f), (ts)) #endif # ifdef SHOW_PROGRESS diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index 9416e6b23..4548f00ab 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1422,7 +1422,7 @@ curses_util_makeStreamFromAddr(XW_UtilCtxt* uc, XP_PlayerAddr channelNo ) static void curses_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* const XP_UNUSED_DBG(msg), - XP_S16 XP_UNUSED_DBG(from) ) + XP_S16 XP_UNUSED_DBG(from), XP_U32 XP_UNUSED(timestamp) ) { CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure; globals->nChatsSent = 0; diff --git a/xwords4/linux/gtkboard.c b/xwords4/linux/gtkboard.c index 13b3b8fed..564ce31ac 100644 --- a/xwords4/linux/gtkboard.c +++ b/xwords4/linux/gtkboard.c @@ -2255,7 +2255,8 @@ gtk_util_makeStreamFromAddr(XW_UtilCtxt* uc, XP_PlayerAddr channelNo ) #ifdef XWFEATURE_CHAT static void -gtk_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* const msg, XP_S16 from ) +gtk_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* const msg, XP_S16 from, + XP_U32 timestamp ) { GtkGameGlobals* globals = (GtkGameGlobals*)uc->closure; XP_UCHAR buf[1024]; @@ -2263,7 +2264,7 @@ gtk_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR* const msg, XP_S16 from ) if ( 0 <= from ) { name = globals->cGlobals.gi->players[from].name; } - XP_SNPRINTF( buf, VSIZE(buf), "quoth %s: %s", name, msg ); + XP_SNPRINTF( buf, VSIZE(buf), "quoth %s at %d: %s", name, timestamp, msg ); (void)gtkask( globals->window, buf, GTK_BUTTONS_OK, NULL ); } #endif