mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-03 23:04:08 +01:00
use notifications and other tweaks
This commit is contained in:
parent
0d7b81ac72
commit
585f55c040
8 changed files with 80 additions and 24 deletions
|
@ -884,11 +884,13 @@ board_canHint( const BoardCtxt* board )
|
||||||
return canHint;
|
return canHint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_CHAT
|
||||||
void
|
void
|
||||||
board_sendChat( const BoardCtxt* board, XWEnv xwe, const XP_UCHAR* msg )
|
board_sendChat( const BoardCtxt* board, XWEnv xwe, const XP_UCHAR* msg )
|
||||||
{
|
{
|
||||||
server_sendChat( board->server, xwe, msg, board->selPlayer );
|
server_sendChat( board->server, xwe, msg, board->selPlayer );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static XP_U16
|
static XP_U16
|
||||||
adjustOffset( XP_U16 curOffset, XP_S16 zoomBy )
|
adjustOffset( XP_U16 curOffset, XP_S16 zoomBy )
|
||||||
|
|
|
@ -553,6 +553,8 @@ game_summarize( XWGame* game, CurGameInfo* gi, GameSummary* summary )
|
||||||
summary->turn = server_getCurrentTurn( server, &summary->turnIsLocal );
|
summary->turn = server_getCurrentTurn( server, &summary->turnIsLocal );
|
||||||
summary->lastMoveTime = server_getLastMoveTime(server);
|
summary->lastMoveTime = server_getLastMoveTime(server);
|
||||||
summary->lang = gi->dictLang;
|
summary->lang = gi->dictLang;
|
||||||
|
summary->gameOver = server_getGameIsOver( server );
|
||||||
|
|
||||||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||||
LocalPlayer* lp = &gi->players[ii];
|
LocalPlayer* lp = &gi->players[ii];
|
||||||
if ( LP_IS_ROBOT(lp) || !LP_IS_LOCAL(lp) ) {
|
if ( LP_IS_ROBOT(lp) || !LP_IS_LOCAL(lp) ) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ typedef struct _GameStateInfo {
|
||||||
|
|
||||||
typedef struct _GameSummary {
|
typedef struct _GameSummary {
|
||||||
XP_Bool turnIsLocal;
|
XP_Bool turnIsLocal;
|
||||||
XP_Bool inPlay;
|
XP_Bool gameOver;
|
||||||
XP_S8 turn;
|
XP_S8 turn;
|
||||||
XP_U32 lastMoveTime;
|
XP_U32 lastMoveTime;
|
||||||
XP_U8 missingPlayers;
|
XP_U8 missingPlayers;
|
||||||
|
|
|
@ -22,7 +22,6 @@ DEBS = cmake
|
||||||
|
|
||||||
INPUTS = main.c wasmdict.c wasmutls.c wasmdraw.c wasmutil.c wasmdutil.c ${COMMONSRC}
|
INPUTS = main.c wasmdict.c wasmutls.c wasmdraw.c wasmutil.c wasmdutil.c ${COMMONSRC}
|
||||||
|
|
||||||
DEFINES += -DXWFEATURE_CHAT
|
|
||||||
DEFINES += -DXWFEATURE_BONUSALL
|
DEFINES += -DXWFEATURE_BONUSALL
|
||||||
DEFINES += -DMAX_ROWS=32
|
DEFINES += -DMAX_ROWS=32
|
||||||
DEFINES += -DCOMMON_LAYOUT
|
DEFINES += -DCOMMON_LAYOUT
|
||||||
|
|
|
@ -95,9 +95,10 @@
|
||||||
// #define GLOBALS_ON_STACK
|
// #define GLOBALS_ON_STACK
|
||||||
|
|
||||||
typedef struct _NewGameParams {
|
typedef struct _NewGameParams {
|
||||||
|
Globals* globals;
|
||||||
bool isRobotNotRemote;
|
bool isRobotNotRemote;
|
||||||
bool hintsNotAllowed;
|
bool hintsNotAllowed;
|
||||||
const char* lc;
|
char lc[8];
|
||||||
} NewGameParams;
|
} NewGameParams;
|
||||||
|
|
||||||
static void updateScreen( GameState* gs, bool doSave );
|
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);
|
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 {
|
typedef struct _ConfirmState {
|
||||||
Globals* globals;
|
Globals* globals;
|
||||||
BoolProc proc;
|
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, " (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",
|
offset += snprintf( buf+offset, sizeof(buf)-offset, " Opponent: %s",
|
||||||
summary.opponents );
|
summary.opponents );
|
||||||
|
offset += snprintf( buf+offset, sizeof(buf)-offset, " My turn: %s",
|
||||||
|
0 <= summary.turn && summary.turnIsLocal ? "YES" : "NO" );
|
||||||
}
|
}
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
replaceStringIfDifferent( globals->mpool, &result, buf );
|
replaceStringIfDifferent( globals->mpool, &result, buf );
|
||||||
|
@ -847,16 +864,17 @@ onConflict( void* closure, const char* ignored )
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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.... */
|
/* This hasn't worked.... */
|
||||||
/* CAST_GLOB(Globals*, globals, closure); */
|
GameState* gs = getCurGame( globals );
|
||||||
/* GameState* gs = getCurGame( globals ); */
|
if ( !!gs ) {
|
||||||
/* if ( !!gs ) { */
|
board_invalAll( gs->game.board );
|
||||||
/* board_invalAll( gs->game.board ); */
|
updateScreen( gs, false );
|
||||||
/* updateScreen( gs, false ); */
|
}
|
||||||
/* } */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1327,8 +1345,10 @@ loadAndDraw( Globals* globals, const NetLaunchInfo* invite,
|
||||||
gs->gi.players[0].isLocal = XP_TRUE;
|
gs->gi.players[0].isLocal = XP_TRUE;
|
||||||
gs->gi.players[0].robotIQ = 0;
|
gs->gi.players[0].robotIQ = 0;
|
||||||
|
|
||||||
gs->gi.players[1].name = copyString( globals->mpool, "Robot" );
|
bool otherLocal = !!params ? params->isRobotNotRemote : true;
|
||||||
gs->gi.players[1].isLocal = !!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 );
|
XP_LOGFF( "set isLocal[1]: %d", gs->gi.players[1].isLocal );
|
||||||
gs->gi.players[1].robotIQ = 99; /* doesn't matter if remote */
|
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 ) ) {
|
if ( game_receiveMessage( &gs->game, NULL, stream, from ) ) {
|
||||||
updateScreen( gs, true );
|
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 {
|
} else {
|
||||||
char msg[128];
|
char msg[128];
|
||||||
snprintf( msg, sizeof(msg), "Dropping move for deleted game (id: %X/%d)",
|
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 ) {
|
if ( 0 <= newTurn && !isVisible(gs) && gs->gi.players[newTurn].isLocal ) {
|
||||||
char msg[128];
|
char msg[128];
|
||||||
snprintf( msg, sizeof(msg),
|
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 );
|
gs->gameName );
|
||||||
call_confirm( gs->globals, msg, openConfirmed, gs );
|
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 );
|
(*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
|
void
|
||||||
onNewGame( void* closure, bool opponentIsRobot, const char* langName )
|
onNewGame( void* closure, bool opponentIsRobot, const char* langName )
|
||||||
{
|
{
|
||||||
Globals* globals = (Globals*)closure;
|
Globals* globals = (Globals*)closure;
|
||||||
XP_LOGFF( "isRobot: %d; lc: %s", opponentIsRobot, langName );
|
XP_LOGFF( "isRobot: %d; lc: %s", opponentIsRobot, langName );
|
||||||
|
|
||||||
char lc[8];
|
NewGameParams* ngp = XP_CALLOC( globals->mpool, sizeof(*ngp) );
|
||||||
langNameToLC(globals, langName, lc, sizeof(lc));
|
ngp->globals = globals;
|
||||||
|
ngp->isRobotNotRemote = opponentIsRobot;
|
||||||
|
langNameToLC(globals, langName, ngp->lc, sizeof(ngp->lc));
|
||||||
|
|
||||||
NewGameParams ngp = { .isRobotNotRemote = opponentIsRobot,
|
if ( !opponentIsRobot && !js_getHaveNotifyPerm() ) {
|
||||||
.lc = lc,
|
const char* msg = "You are creating a networked game. Would you like "
|
||||||
};
|
"notifications when a move arrives and it becomes your turn?";
|
||||||
loadAndDraw( globals, NULL, 0, &ngp );
|
call_confirm( globals, msg, onAllowNotify, ngp );
|
||||||
updateDeviceButtons( globals );
|
} else {
|
||||||
|
onAllowNotify(ngp, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from js with a proc and closure */
|
/* Called from js with a proc and closure */
|
||||||
|
|
|
@ -67,6 +67,8 @@ typedef struct Globals {
|
||||||
CommonPrefs cp;
|
CommonPrefs cp;
|
||||||
DictMgrCtxt* dictMgr;
|
DictMgrCtxt* dictMgr;
|
||||||
|
|
||||||
|
bool focussed; /* window is in foreground */
|
||||||
|
|
||||||
char playerName[32];
|
char playerName[32];
|
||||||
|
|
||||||
#ifdef MEM_DEBUG
|
#ifdef MEM_DEBUG
|
||||||
|
|
|
@ -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_informMissing, wasm );
|
||||||
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_addrChange, wasm );
|
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_addrChange, wasm );
|
||||||
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_informWordsBlocked, wasm );
|
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_informWordsBlocked, wasm );
|
||||||
|
#ifdef XWFEATURE_CHAT
|
||||||
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_showChat, wasm );
|
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_showChat, wasm );
|
||||||
|
#endif
|
||||||
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_getDevUtilCtxt, wasm );
|
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_getDevUtilCtxt, wasm );
|
||||||
|
|
||||||
size_t sizeInBytes = sizeof(*wuctxt->super.vtable);
|
size_t sizeInBytes = sizeof(*wuctxt->super.vtable);
|
||||||
|
|
|
@ -131,7 +131,10 @@ function jssetup(closure, dbg, devid, gitrev, now, noTabProc, focusProc, msgProc
|
||||||
window.addEventListener('storage', listener);
|
window.addEventListener('storage', listener);
|
||||||
|
|
||||||
window.onfocus = function () {
|
window.onfocus = function () {
|
||||||
ccallString(focusProc, state.closure, '');
|
ccallString(focusProc, state.closure, 'focus');
|
||||||
|
};
|
||||||
|
window.onblur = function () {
|
||||||
|
ccallString(focusProc, state.closure, 'blur');
|
||||||
};
|
};
|
||||||
|
|
||||||
state.closure = closure;
|
state.closure = closure;
|
||||||
|
|
Loading…
Reference in a new issue