diff --git a/xwords4/android/XWords4/archive/R.java b/xwords4/android/XWords4/archive/R.java index 4579b70f2..209638e3c 100644 --- a/xwords4/android/XWords4/archive/R.java +++ b/xwords4/android/XWords4/archive/R.java @@ -2435,6 +2435,7 @@ public final class R { placed, i.e. they do not form a single word. */ public static final int str_no_empties_in_turn=0x7f05017d; + public static final int str_no_hint_found=0x7f05030a; /** Same as above, but used when you try to show tiles belonging to a player on another device (a remote player.) */ diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index dfe48c0a8..0627d365a 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -2529,4 +2529,6 @@ Use Bluetooth to play against a nearby device that\'s \"paired\" with yours. + Cannot find any moves + diff --git a/xwords4/android/XWords4/res_src/values-ba_CK/strings.xml b/xwords4/android/XWords4/res_src/values-ba_CK/strings.xml index e3b4195f7..4899b352d 100644 --- a/xwords4/android/XWords4/res_src/values-ba_CK/strings.xml +++ b/xwords4/android/XWords4/res_src/values-ba_CK/strings.xml @@ -2178,4 +2178,5 @@ i.e. yreve reirrac ni eht dlrow tpecxe Nozirev dna Tnirps. Esu Htooteulb ot yalp tsniaga a ybraen ecived taht\'s \"deriap\" htiw sruoy. + Tonnac dnif yna sevom diff --git a/xwords4/android/XWords4/res_src/values-ca_PS/strings.xml b/xwords4/android/XWords4/res_src/values-ca_PS/strings.xml index ad10613b9..bfb9818ba 100644 --- a/xwords4/android/XWords4/res_src/values-ca_PS/strings.xml +++ b/xwords4/android/XWords4/res_src/values-ca_PS/strings.xml @@ -2178,4 +2178,5 @@ I.E. EVERY CARRIER IN THE WORLD EXCEPT VERIZON AND SPRINT. USE BLUETOOTH TO PLAY AGAINST A NEARBY DEVICE THAT\'S \"PAIRED\" WITH YOURS. + CANNOT FIND ANY MOVES diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDelegate.java index 3bff32314..d11b650d8 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDelegate.java @@ -1719,6 +1719,7 @@ public class BoardDelegate extends DelegateBase public void userError( int code ) { int resid = 0; + boolean asToast = false; switch( code ) { case UtilCtxt.ERR_TILES_NOT_IN_LINE: resid = R.string.str_tiles_not_in_line; @@ -1764,10 +1765,23 @@ public class BoardDelegate extends DelegateBase case ERR_REG_SERVER_SANS_REMOTE: resid = R.string.str_reg_server_sans_remote; break; + case ERR_NO_HINT_FOUND: + resid = R.string.str_no_hint_found; + asToast = true; + break; } if ( resid != 0 ) { - nonBlockingDialog( DlgID.DLG_OKONLY, getString( resid ) ); + if ( asToast ) { + final int residf = resid; + runOnUiThread( new Runnable() { + public void run() { + showToast( residf ); + } + } ); + } else { + nonBlockingDialog( DlgID.DLG_OKONLY, getString( resid ) ); + } } } // userError diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesListDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesListDelegate.java index 417a3b98a..dd444de14 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesListDelegate.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesListDelegate.java @@ -1598,6 +1598,7 @@ public class GamesListDelegate extends ListDelegateBase for ( long row : rows ) { m_selGames.remove( row ); } + invalidateOptionsMenuIf(); setTitleBar(); } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java index 82c6246f8..d4bf807aa 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java @@ -125,7 +125,9 @@ public interface UtilCtxt { static final int ERR_NO_EMPTY_TRADE = 13; static final int ERR_CANT_UNDO_TILEASSIGN = 14; static final int ERR_CANT_HINT_WHILE_DISABLED = 15; - static final int ERR_RELAY_BASE = 16; + static final int ERR_NO_HINT_FOUND = 16; + + static final int ERR_RELAY_BASE = 17; void userError( int id ); void informMove( String expl, String words ); diff --git a/xwords4/android/scripts/common_targets.xml b/xwords4/android/scripts/common_targets.xml index 9ca2678c6..ef91f60e6 100644 --- a/xwords4/android/scripts/common_targets.xml +++ b/xwords4/android/scripts/common_targets.xml @@ -110,4 +110,16 @@ + + + + + + + + Created XWords4-debug-${git-rev}.apk + + + + diff --git a/xwords4/android/scripts/info.py b/xwords4/android/scripts/info.py index 310758fd9..cd435e68f 100755 --- a/xwords4/android/scripts/info.py +++ b/xwords4/android/scripts/info.py @@ -1,7 +1,7 @@ #!/usr/bin/python # Script meant to be installed on eehouse.org. -import logging, shelve, hashlib, sys, json, subprocess, glob, os, struct, random +import logging, shelve, hashlib, sys, json, subprocess, glob, os, struct, random, string import mk_for_download, mygit import xwconfig @@ -161,10 +161,13 @@ def getDictSums(): openShelf() return s_shelf[k_SUMS] -def getOrderedApks( path ): +def getOrderedApks( path, debug ): + # logging.debug( "getOrderedApks(" + path + ")" ) apks = [] - pattern = path + "/XWords4-release_*android_beta_*.apk" + pattern = path + if debug: pattern += "/XWords4-debug-android_*.apk" + else: pattern += "/XWords4-release_*android_beta_*.apk" files = ((os.stat(apk).st_mtime, apk) for apk in glob.glob(pattern)) for mtime, file in sorted(files, reverse=True): @@ -173,6 +176,14 @@ def getOrderedApks( path ): return apks +def getVariantDir( name ): + result = '' + splits = string.split( name, '.' ) + last = splits[-1] + if not last == 'xw4': result = last + '/' + # logging.debug( 'getVariantDir(' + name + ") => " + result ) + return result + # public, but deprecated def curVersion( req, name, avers = 41, gvers = None, installer = None ): global k_versions @@ -218,12 +229,22 @@ def getApp( params, name ): if k_NAME in params: name = params[k_NAME] if name: + variantDir = getVariantDir( name ) # If we're a dev device, always push the latest if k_DEBUG in params and params[k_DEBUG]: - url = k_urlbase + '/' + k_apkDir + 'XWords4-debug.apk' - result = {k_URL: url} + dir = k_filebase + k_apkDir + variantDir + apks = getOrderedApks( dir, True ) + if 0 < len(apks): + apk = apks[0] + curApk = params[k_GVERS] + '.apk' + if curApk in apk: + logging.debug( "already have " + curApk ) + else: + url = k_urlbase + '/' + k_apkDir + variantDir + apk[len(dir):] + logging.debug("url: " + url) + result = {k_URL: url} elif k_DEVOK in params and params[k_DEVOK]: - apks = getOrderedApks( k_filebase + k_apkDir ) + apks = getOrderedApks( k_filebase + k_apkDir, False ) if 0 < len(apks): apk = apks[0] # Does path NOT contain name of installed file @@ -439,7 +460,6 @@ def getUpdates( req, params ): else: logging.debug( "NOT FOUND xlate info" ) - logging.debug( 'getUpdates done:', ) result = json.dumps( result ) # logging.debug( result ) return result @@ -494,7 +514,7 @@ def main(): if argc >= 4: usage() path = "" if argc >= 3: path = sys.argv[2] - apks = getOrderedApks( path ) + apks = getOrderedApks( path, False ) if 0 == len(apks): print "No apks in", path for apk in apks: print apk diff --git a/xwords4/common/board.c b/xwords4/common/board.c index 97003fd88..241ae8636 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -2107,6 +2107,7 @@ board_requestHint( BoardCtxt* board, if ( searchComplete && canMove ) { model_makeTurnFromMoveInfo( model, selPlayer, &newMove); } else { + result = XP_FALSE; XP_STATUSF( "unable to complete hint request\n" ); } *workRemainsP = !searchComplete; @@ -2122,6 +2123,10 @@ board_requestHint( BoardCtxt* board, setArrowVisible( board, wasVisible ); } } + + if ( !result ) { + util_userError( board->util, ERR_NO_HINT_FOUND ); + } } return result || redraw; } /* board_requestHint */ diff --git a/xwords4/common/engine.c b/xwords4/common/engine.c index ecb7c5830..b1aa40c62 100644 --- a/xwords4/common/engine.c +++ b/xwords4/common/engine.c @@ -393,6 +393,7 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model, { XP_Bool result = XP_TRUE; XP_U16 star_row; + XP_Bool canMove = XP_FALSE; engine->nTilesMax = XP_MIN( MAX_TRAY_TILES, nTiles ); #ifdef XWFEATURE_BONUSALL @@ -445,9 +446,9 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model, dictionary's emtpy or there are no tiles, still return TRUE so we don't get scheduled again. Fixes infinite loop with empty dict and a robot. */ - *canMoveP = NULL != dict_getTopEdge(engine->dict) + canMove = NULL != dict_getTopEdge(engine->dict) && initTray( engine, tiles, nTiles ); - if ( *canMoveP ) { + if ( canMove ) { util_engineStarting( engine->util, engine->rack[engine->blankTile] ); @@ -528,6 +529,7 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model, XP_MEMCPY( newMove, &move->moveInfo, sizeof(*newMove) ); } else { newMove->nTiles = 0; + canMove = XP_FALSE; } result = XP_TRUE; } @@ -540,6 +542,7 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model, newMove->nTiles = 0; } + *canMoveP = canMove; return result; } /* engine_findMove */ diff --git a/xwords4/common/util.h b/xwords4/common/util.h index 06a55f4de..02f093a5f 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -58,6 +58,7 @@ typedef enum { /* ERR_NOT_YOUR_TURN_TO_MOVE, */ ERR_CANT_UNDO_TILEASSIGN, ERR_CANT_HINT_WHILE_DISABLED, + ERR_NO_HINT_FOUND, /* not really an error... */ ERR_RELAY_BASE, ERR_RELAY_END = ERR_RELAY_BASE + XWRELAY_ERROR_LASTERR diff --git a/xwords4/linux/linuxutl.c b/xwords4/linux/linuxutl.c index 0f16539ed..2920777a0 100644 --- a/xwords4/linux/linuxutl.c +++ b/xwords4/linux/linuxutl.c @@ -492,6 +492,10 @@ linux_getErrString( UtilErrID id, XP_Bool* silent ) message = "No tiles selected; trade cancelled."; break; + case ERR_NO_HINT_FOUND: + message = "Unable to suggest any moves."; + break; + case ERR_CANT_UNDO_TILEASSIGN: message = "Tile assignment can't be undone."; break;