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.
This commit is contained in:
Eric House 2017-06-08 13:04:59 -07:00
parent 6f0fb66a0d
commit 0b0a50bd5c
13 changed files with 92 additions and 43 deletions

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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 );
}

View file

@ -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<ContentValues> valuess = new ArrayList<ContentValues>();
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 );

View file

@ -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 );

View file

@ -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 );
}

View file

@ -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" );
}

View file

@ -13,4 +13,11 @@
android:layout_width="0dp"
android:layout_weight="1"
/>
<TextView android:id="@+id/chat_row_time"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:singleLine="true"
android:layout_width="0dp"
android:layout_weight="1"
/>
</TableRow>

View file

@ -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();
}

View file

@ -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 ) ) {

View file

@ -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

View file

@ -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;

View file

@ -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