use notifications and other tweaks

This commit is contained in:
Eric House 2021-03-09 20:13:42 -08:00
parent 0d7b81ac72
commit 585f55c040
8 changed files with 80 additions and 24 deletions

View file

@ -884,11 +884,13 @@ board_canHint( const BoardCtxt* board )
return canHint;
}
#ifdef XWFEATURE_CHAT
void
board_sendChat( const BoardCtxt* board, XWEnv xwe, const XP_UCHAR* msg )
{
server_sendChat( board->server, xwe, msg, board->selPlayer );
}
#endif
static XP_U16
adjustOffset( XP_U16 curOffset, XP_S16 zoomBy )

View file

@ -553,6 +553,8 @@ game_summarize( XWGame* game, CurGameInfo* gi, GameSummary* summary )
summary->turn = server_getCurrentTurn( server, &summary->turnIsLocal );
summary->lastMoveTime = server_getLastMoveTime(server);
summary->lang = gi->dictLang;
summary->gameOver = server_getGameIsOver( server );
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
LocalPlayer* lp = &gi->players[ii];
if ( LP_IS_ROBOT(lp) || !LP_IS_LOCAL(lp) ) {

View file

@ -53,7 +53,7 @@ typedef struct _GameStateInfo {
typedef struct _GameSummary {
XP_Bool turnIsLocal;
XP_Bool inPlay;
XP_Bool gameOver;
XP_S8 turn;
XP_U32 lastMoveTime;
XP_U8 missingPlayers;

View file

@ -22,7 +22,6 @@ DEBS = cmake
INPUTS = main.c wasmdict.c wasmutls.c wasmdraw.c wasmutil.c wasmdutil.c ${COMMONSRC}
DEFINES += -DXWFEATURE_CHAT
DEFINES += -DXWFEATURE_BONUSALL
DEFINES += -DMAX_ROWS=32
DEFINES += -DCOMMON_LAYOUT

View file

@ -95,9 +95,10 @@
// #define GLOBALS_ON_STACK
typedef struct _NewGameParams {
Globals* globals;
bool isRobotNotRemote;
bool hintsNotAllowed;
const char* lc;
char lc[8];
} NewGameParams;
static void updateScreen( GameState* gs, bool doSave );
@ -248,6 +249,22 @@ EM_JS(void, js_callNewGame, (const char* msg, void* closure,
nbGetNewGame(closure, jsmsg, jlangs);
});
EM_JS(bool, js_getHaveNotifyPerm, (), {
let perm = Notification.permission;
return perm == 'granted';
});
EM_JS(void, js_requestNotify, (), {
Notification.requestPermission();
});
EM_JS( void, js_notify, (const char* msg), {
const jsmsg = UTF8ToString(msg);
new Notification('WASM CrossWords',
{ body: jsmsg, renotify: true, }
);
});
typedef struct _ConfirmState {
Globals* globals;
BoolProc proc;
@ -585,10 +602,10 @@ formatForGame(Globals* globals, bool multiLangs, const XP_UCHAR* gameKey )
offset += snprintf( buf+offset, sizeof(buf)-offset, " (in %s)", langName );
}
}
offset += snprintf( buf+offset, sizeof(buf)-offset, " My turn: %s",
summary.turnIsLocal ? "YES" : "NO" );
offset += snprintf( buf+offset, sizeof(buf)-offset, " Opponent: %s",
summary.opponents );
offset += snprintf( buf+offset, sizeof(buf)-offset, " My turn: %s",
0 <= summary.turn && summary.turnIsLocal ? "YES" : "NO" );
}
char* result = NULL;
replaceStringIfDifferent( globals->mpool, &result, buf );
@ -847,16 +864,17 @@ onConflict( void* closure, const char* ignored )
}
static void
onFocussed( void* closure, const char* ignored )
onFocussed( void* closure, const char* newState )
{
XP_LOGFF("Need to refresh...");
CAST_GLOB(Globals*, globals, closure);
globals->focussed = 0 == strcmp("focus", newState);
XP_LOGFF( "focussed now: %d", globals->focussed );
/* This hasn't worked.... */
/* CAST_GLOB(Globals*, globals, closure); */
/* GameState* gs = getCurGame( globals ); */
/* if ( !!gs ) { */
/* board_invalAll( gs->game.board ); */
/* updateScreen( gs, false ); */
/* } */
GameState* gs = getCurGame( globals );
if ( !!gs ) {
board_invalAll( gs->game.board );
updateScreen( gs, false );
}
}
static void
@ -1327,8 +1345,10 @@ loadAndDraw( Globals* globals, const NetLaunchInfo* invite,
gs->gi.players[0].isLocal = XP_TRUE;
gs->gi.players[0].robotIQ = 0;
gs->gi.players[1].name = copyString( globals->mpool, "Robot" );
gs->gi.players[1].isLocal = !!params ? params->isRobotNotRemote : true;
bool otherLocal = !!params ? params->isRobotNotRemote : true;
gs->gi.players[1].name = copyString( globals->mpool,
otherLocal ? "Robot" : "(remote)" );
gs->gi.players[1].isLocal = otherLocal;
XP_LOGFF( "set isLocal[1]: %d", gs->gi.players[1].isLocal );
gs->gi.players[1].robotIQ = 99; /* doesn't matter if remote */
@ -1387,6 +1407,15 @@ main_onGameMessage( Globals* globals, XP_U32 gameID,
if ( game_receiveMessage( &gs->game, NULL, stream, from ) ) {
updateScreen( gs, true );
}
if ( !globals->focussed && js_getHaveNotifyPerm() ) {
GameSummary summary;
game_summarize( &gs->game, &gs->gi, &summary );
if ( summary.turnIsLocal ) {
char buf[128];
sprintf( buf, "Your turn in game %s", gs->gameName );
js_notify( buf );
}
}
} else {
char msg[128];
snprintf( msg, sizeof(msg), "Dropping move for deleted game (id: %X/%d)",
@ -1473,7 +1502,7 @@ main_turnChanged( GameState* gs, int newTurn )
if ( 0 <= newTurn && !isVisible(gs) && gs->gi.players[newTurn].isLocal ) {
char msg[128];
snprintf( msg, sizeof(msg),
"It's your turn in background game \"%s\". Would you like to open it now?",
"It's your turn in game \"%s\". Would you like to open it now?",
gs->gameName );
call_confirm( gs->globals, msg, openConfirmed, gs );
}
@ -1850,20 +1879,37 @@ cbckBinary( BinProc proc, void* closure, int len, const uint8_t* msg )
(*proc)(closure, msg, len );
}
static void
onAllowNotify(void* closure, bool confirmed)
{
NewGameParams* ngp = (NewGameParams*)closure;
Globals* globals = ngp->globals;
if ( confirmed ) {
js_requestNotify();
}
loadAndDraw( globals, NULL, 0, ngp );
updateDeviceButtons( globals );
XP_FREE( globals->mpool, ngp );
}
void
onNewGame( void* closure, bool opponentIsRobot, const char* langName )
{
Globals* globals = (Globals*)closure;
XP_LOGFF( "isRobot: %d; lc: %s", opponentIsRobot, langName );
char lc[8];
langNameToLC(globals, langName, lc, sizeof(lc));
NewGameParams* ngp = XP_CALLOC( globals->mpool, sizeof(*ngp) );
ngp->globals = globals;
ngp->isRobotNotRemote = opponentIsRobot;
langNameToLC(globals, langName, ngp->lc, sizeof(ngp->lc));
NewGameParams ngp = { .isRobotNotRemote = opponentIsRobot,
.lc = lc,
};
loadAndDraw( globals, NULL, 0, &ngp );
updateDeviceButtons( globals );
if ( !opponentIsRobot && !js_getHaveNotifyPerm() ) {
const char* msg = "You are creating a networked game. Would you like "
"notifications when a move arrives and it becomes your turn?";
call_confirm( globals, msg, onAllowNotify, ngp );
} else {
onAllowNotify(ngp, false);
}
}
/* Called from js with a proc and closure */

View file

@ -67,6 +67,8 @@ typedef struct Globals {
CommonPrefs cp;
DictMgrCtxt* dictMgr;
bool focussed; /* window is in foreground */
char playerName[32];
#ifdef MEM_DEBUG

View file

@ -590,7 +590,9 @@ wasm_util_make( MPFORMAL CurGameInfo* gi, XW_DUtilCtxt* dctxt, GameState* closur
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_informMissing, wasm );
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_addrChange, wasm );
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_informWordsBlocked, wasm );
#ifdef XWFEATURE_CHAT
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_showChat, wasm );
#endif
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_getDevUtilCtxt, wasm );
size_t sizeInBytes = sizeof(*wuctxt->super.vtable);

View file

@ -131,7 +131,10 @@ function jssetup(closure, dbg, devid, gitrev, now, noTabProc, focusProc, msgProc
window.addEventListener('storage', listener);
window.onfocus = function () {
ccallString(focusProc, state.closure, '');
ccallString(focusProc, state.closure, 'focus');
};
window.onblur = function () {
ccallString(focusProc, state.closure, 'blur');
};
state.closure = closure;