offer to turn on dual-pane mode for upgraders

When a device is a tablet and not a first-time install, put up an offer
to enable dual-pane mode. Change confirm-alerts to include
do-not-show-again box, and use that. Add menu item, hidden when not in
dual-pane mode, to turn it back off. Exit app after posting a
notification and a toast on changing that preference so it'll take
effect.
This commit is contained in:
Eric House 2016-08-02 21:49:17 -07:00
parent f56869b9ea
commit 08269c8962
11 changed files with 929 additions and 790 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Remove this once dualpane is well tested -->
<item android:id="@+id/games_menu_disable_dualpane"
android:title="@string/disable_dualpane"
/>
<item android:id="@+id/games_menu_newgame_solo"
android:title="@string/new_game"
android:icon="@drawable/content_new_solo__gen"

View file

@ -67,7 +67,7 @@
<string name="key_summary_field">key_summary_field</string>
<string name="key_default_loc">key_default_loc</string>
<string name="key_force_tablet">key_force_tablet</string>
<string name="key_enable_dualpane">key_enable_dualpane</string>
<string name="key_enable_dualpane">key_enable_dualpane2</string>
<string name="key_force_radio">key_force_radio</string>
<string name="key_addrs_pref">key_addrs_pref</string>
@ -91,6 +91,7 @@
<string name="key_notagain_sync">key_notagain_sync</string>
<!-- <string name="key_notagain_sms_ready">key_notagain_sms_ready</string> -->
<string name="key_notagain_newselect">key_notagain_newselect</string>
<string name="key_notagain_dualpane">key_notagain_dualpane</string>
<string name="key_notagain_backclears">key_notagain_backclears</string>
<string name="key_notagain_chat">key_notagain_chat</string>
<string name="key_notagain_relay">key_notagain_relay</string>

View file

@ -2597,7 +2597,6 @@
<string name="pref_group_relay_title">Relay Stuff</string>
<string name="pref_group_relay_summary">Prefs related to play via internet/relay</string>
<string name="pref_group_l10n_title">Localization Stuff</string>
<string name="pref_group_tablets_title">Tablets Stuff</string>
<string name="pref_group_l10n_summary">Prefs related to in-app localization</string>
<string name="pref_item_update_title">Update between releases</string>
<string name="pref_item_update_summary">Get intermediate builds</string>
@ -2689,4 +2688,22 @@
name before you create this game?</string>
<string name="no_invites">This game has sent no invitations</string>
<string name="invite_dualpane">You appear to be running a
tablet-sized device. Would you like to try an experimental new
feature that lets you view two panes (e.g. board and chat)
side-by-side when your device is horizontal?
\n\nYou can disable the feature later using the new \"Disable
side-by-side\" menu item. Or via App Settings.
\n\nPlease let me know if you like the feature, report crashes, make
suggestions, etc.!!</string>
<string name="enable_dualpane">Enable side-by-side</string>
<string name="post_dualpane_title">Relaunch after change</string>
<string name="post_dualpane_on_body">Start Crosswords with side-by-side enabled!</string>
<string name="post_dualpane_off_body">Start Crosswords with side-by-side disabled</string>
<string name="disable_dualpane">Disable side-by-side</string>
<string name="dualpane_restart">Exiting app…</string>
</resources>

View file

@ -116,6 +116,12 @@
android:defaultValue="@string/game_summary_field_opponents"
/>
<CheckBoxPreference android:key="@string/key_enable_dualpane"
android:title="@string/enable_dualpane_title"
android:summary="@string/enable_dualpane_summary"
android:defaultValue="false"
/>
<CheckBoxPreference android:key="@string/key_hide_title"
android:title="@string/hide_title"
android:summary="@string/hide_title_summary"
@ -424,19 +430,11 @@
/>
</PreferenceScreen>
<PreferenceScreen android:title="@string/pref_group_tablets_title"
>
<CheckBoxPreference android:key="@string/key_enable_dualpane"
android:title="@string/enable_dualpane_title"
android:summary="@string/enable_dualpane_summary"
android:defaultValue="false"
/>
<CheckBoxPreference android:key="@string/key_force_tablet"
android:title="@string/force_tablet_title"
android:summary="@string/force_tablet_summary"
android:defaultValue="false"
/>
</PreferenceScreen>
<CheckBoxPreference android:key="@string/key_force_tablet"
android:title="@string/force_tablet_title"
android:summary="@string/force_tablet_summary"
android:defaultValue="false"
/>
<PreferenceScreen android:title="@string/pref_group_l10n_title"
android:summary="@string/pref_group_l10n_summary"

View file

@ -2228,7 +2228,6 @@
<string name="pref_group_relay_title">Yaler Ffuts</string>
<string name="pref_group_relay_summary">Sferp detaler ot yalp aiv yaler/tenretni</string>
<string name="pref_group_l10n_title">Noitazilacol Ffuts</string>
<string name="pref_group_tablets_title">Stelbat Ffuts</string>
<string name="pref_group_l10n_summary">Sferp detaler ot ppa-ni noitazilacol</string>
<string name="pref_item_update_title">Etadpu neewteb sesaeler</string>
<string name="pref_item_update_summary">Teg etaidemretni sdliub</string>
@ -2299,4 +2298,20 @@
reyalp eman \"%1$s\". Dluow uoy ekil ot ezilanosrep htiw ruoy nwo
eman erofeb uoy etaerc siht ?emag</string>
<string name="no_invites">Siht emag sah tnes on snoitativni</string>
<string name="invite_dualpane">Uoy raeppa ot eb gninnur a
dezis-telbat ecived. Dluow uoy ekil ot yrt na latnemirepxe wen
erutaef taht stel uoy weiv owt senap e(.g. draob dna )tahc
edis-yb-edis nehw ruoy ecived si ?latnoziroh
\n\nUoy nac elbasid eht erutaef retal gnisu eht wen \"Elbasid
edis-yb-edis\" unem meti. Ro aiv Ppa Sgnittes.
\n\nEsaelp tel em wonk fi uoy ekil eht ,erutaef troper ,sehsarc ekam
,snoitseggus cte.!!</string>
<string name="enable_dualpane">Elbane edis-yb-edis</string>
<string name="post_dualpane_title">Hcnualer retfa egnahc</string>
<string name="post_dualpane_on_body">Trats Sdrowssorc htiw edis-yb-edis !delbane</string>
<string name="post_dualpane_off_body">Trats Sdrowssorc htiw edis-yb-edis delbasid</string>
<string name="disable_dualpane">Elbasid edis-yb-edis</string>
<string name="dualpane_restart">Gnitixe ppa…</string>
</resources>

View file

@ -2228,7 +2228,6 @@
<string name="pref_group_relay_title">RELAY STUFF</string>
<string name="pref_group_relay_summary">PREFS RELATED TO PLAY VIA INTERNET/RELAY</string>
<string name="pref_group_l10n_title">LOCALIZATION STUFF</string>
<string name="pref_group_tablets_title">TABLETS STUFF</string>
<string name="pref_group_l10n_summary">PREFS RELATED TO IN-APP LOCALIZATION</string>
<string name="pref_item_update_title">UPDATE BETWEEN RELEASES</string>
<string name="pref_item_update_summary">GET INTERMEDIATE BUILDS</string>
@ -2299,4 +2298,20 @@
PLAYER NAME \"%1$s\". WOULD YOU LIKE TO PERSONALIZE WITH YOUR OWN
NAME BEFORE YOU CREATE THIS GAME?</string>
<string name="no_invites">THIS GAME HAS SENT NO INVITATIONS</string>
<string name="invite_dualpane">YOU APPEAR TO BE RUNNING A
TABLET-SIZED DEVICE. WOULD YOU LIKE TO TRY AN EXPERIMENTAL NEW
FEATURE THAT LETS YOU VIEW TWO PANES (E.G. BOARD AND CHAT)
SIDE-BY-SIDE WHEN YOUR DEVICE IS HORIZONTAL?
\n\nYOU CAN DISABLE THE FEATURE LATER USING THE NEW \"DISABLE
SIDE-BY-SIDE\" MENU ITEM. OR VIA APP SETTINGS.
\n\nPLEASE LET ME KNOW IF YOU LIKE THE FEATURE, REPORT CRASHES, MAKE
SUGGESTIONS, ETC.!!</string>
<string name="enable_dualpane">ENABLE SIDE-BY-SIDE</string>
<string name="post_dualpane_title">RELAUNCH AFTER CHANGE</string>
<string name="post_dualpane_on_body">START CROSSWORDS WITH SIDE-BY-SIDE ENABLED!</string>
<string name="post_dualpane_off_body">START CROSSWORDS WITH SIDE-BY-SIDE DISABLED</string>
<string name="disable_dualpane">DISABLE SIDE-BY-SIDE</string>
<string name="dualpane_restart">EXITING APP…</string>
</resources>

View file

@ -549,6 +549,12 @@ public class DelegateBase implements DlgClickNotify,
m_dlgDelegate.showConfirmThen( msg, posButton, action, params );
}
public void showConfirmThen( DlgDelegate.NAKey nakey, int msgId,
int posButtonId, Action action )
{
m_dlgDelegate.showConfirmThen( nakey, msgId, posButtonId, action );
}
protected void showConfirmThen( int msgID, Action action )
{
m_dlgDelegate.showConfirmThen( msgID, action );
@ -557,8 +563,8 @@ public class DelegateBase implements DlgClickNotify,
public void showConfirmThen( Runnable onNA, String msg, int posButton,
int negButton, Action action, Object... params )
{
m_dlgDelegate.showConfirmThen( onNA, msg, posButton, negButton, action,
params );
m_dlgDelegate.showConfirmThen( null, onNA, msg, posButton, negButton,
action, params );
}
protected boolean post( Runnable runnable )

View file

@ -24,6 +24,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface;
@ -69,6 +70,7 @@ public class DlgDelegate {
SET_HIDE_NEWGAME_BUTTONS,
DWNLD_LOC_DICT,
NEW_GAME_DFLT_NAME,
ENABLE_DUALPANE,
// BoardDelegate
UNDO_LAST_ACTION,
@ -135,6 +137,23 @@ public class DlgDelegate {
public Object[] params; // null for now
}
// typesafe int, basically
public static class NAKey implements Runnable {
private Context m_context;
private int m_nakey;
public NAKey(int key) { m_nakey = key; }
boolean isSet( Context context ) {
m_context = context; // hack!!!
return XWPrefs.getPrefsBoolean( context, m_nakey, false );
}
@Override
public void run() {
Assert.assertNotNull( m_context );
XWPrefs.setPrefsBoolean( m_context, m_nakey, true );
}
}
public static final int SMS_BTN = AlertDialog.BUTTON_POSITIVE;
public static final int NFC_BTN = AlertDialog.BUTTON_NEUTRAL;
public static final int DISMISS_BUTTON = 0;
@ -374,41 +393,55 @@ public class DlgDelegate {
public void showConfirmThen( int msg, int posButton, int negButton, Action action )
{
showConfirmThen( null, getString(msg), posButton, negButton, action, null );
showConfirmThen( null, null, getString(msg), posButton, negButton, action, null );
}
public void showConfirmThen( String msg, int posButton, int negButton, Action action )
{
showConfirmThen( null, msg, posButton, negButton, action, null );
showConfirmThen( null, null, msg, posButton, negButton, action, null );
}
public void showConfirmThen( int msg, int posButton, int negButton, Action action,
Object... params )
{
showConfirmThen( null, getString(msg), posButton, negButton, action, params );
showConfirmThen( null, null, getString(msg), posButton, negButton, action, params );
}
public void showConfirmThen( int msg, int posButton, Action action,
Object[] params )
{
showConfirmThen( null, getString(msg), posButton, android.R.string.cancel,
showConfirmThen( null, null, getString(msg), posButton, android.R.string.cancel,
action, params );
}
public void showConfirmThen( Runnable onNA, String msg, int posButton, Action action,
Object[] params )
{
showConfirmThen( onNA, msg, posButton, android.R.string.cancel, action,
showConfirmThen( null, onNA, msg, posButton, android.R.string.cancel, action,
params );
}
public void showConfirmThen( Runnable onNA, String msg, int posButton,
public void showConfirmThen( NAKey nakey, int msgId, int posButtonId,
Action action )
{
showConfirmThen( nakey, null, getString(msgId), posButtonId,
android.R.string.cancel, action, null );
}
public void showConfirmThen( NAKey nakey, Runnable onNA, String msg, int posButton,
int negButton, Action action, Object[] params )
{
DlgState state = new DlgState( DlgID.CONFIRM_THEN, onNA, msg, posButton,
negButton, action, 0, params );
addState( state );
showDialog( DlgID.CONFIRM_THEN );
if ( null != nakey ) {
Assert.assertNull( onNA );
onNA = nakey; // so the run() method will be called to set the key
}
if ( null == nakey || !nakey.isSet( m_activity ) ) {
DlgState state
= new DlgState( DlgID.CONFIRM_THEN, onNA, msg, posButton,
negButton, action, 0, params );
addState( state );
showDialog( DlgID.CONFIRM_THEN );
}
}
public void showInviteChoicesThen( final Action action,

View file

@ -63,6 +63,7 @@ import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DlgDelegate.ActionPair;
import org.eehouse.android.xw4.DlgDelegate.NAKey;
import org.eehouse.android.xw4.DwnldDelegate.DownloadFinishedListener;
import org.eehouse.android.xw4.DwnldDelegate.OnGotLcDictListener;
import org.eehouse.android.xw4.jni.*;
@ -947,11 +948,22 @@ public class GamesListDelegate extends ListDelegateBase
DBUtils.setDBChangeListener( this );
boolean isUpgrade = Utils.firstBootThisVersion( m_activity );
if ( isUpgrade && !s_firstShown ) {
if ( LocUtils.getCurLangCode( m_activity ).equals( "en" ) ) {
FirstRunDialog.show( m_activity );
if ( true || isUpgrade ) {
if ( !s_firstShown ) {
if ( LocUtils.getCurLangCode( m_activity ).equals( "en" ) ) {
FirstRunDialog.show( m_activity );
}
s_firstShown = true;
}
if ( !XWPrefs.getPrefsBoolean( m_activity,
R.string.key_enable_dualpane, false )
&& XWPrefs.getIsTablet( m_activity ) ) {
showConfirmThen( new NAKey(R.string.key_notagain_dualpane),
R.string.invite_dualpane,
R.string.enable_dualpane,
Action.ENABLE_DUALPANE );
}
s_firstShown = true;
}
m_newGameButtons = new Button[] {
@ -1256,6 +1268,9 @@ public class GamesListDelegate extends ListDelegateBase
case OPEN_GAME:
doOpenGame( params );
break;
case ENABLE_DUALPANE:
setDualpaneAndFinish( true );
break;
case CLEAR_SELS:
clearSelections();
break;
@ -1429,6 +1444,10 @@ public class GamesListDelegate extends ListDelegateBase
0 < DBUtils.getGamesWithSendsPending( m_activity ).size();
Utils.setItemVisible( menu, R.id.games_menu_resend, enable );
enable = XWPrefs.getPrefsBoolean( m_activity, R.string.key_enable_dualpane,
false );
Utils.setItemVisible( menu, R.id.games_menu_disable_dualpane, enable );
Assert.assertTrue( m_menuPrepared );
} else {
DbgUtils.logf( "onPrepareOptionsMenu: incomplete so bailing" );
@ -1461,6 +1480,10 @@ public class GamesListDelegate extends ListDelegateBase
switch ( itemID ) {
// There's no selection for these items, so nothing to clear
case R.id.games_menu_disable_dualpane:
setDualpaneAndFinish( false );
break;
case R.id.games_menu_resend:
GameUtils.resendAllIf( m_activity, null, true );
break;
@ -2520,6 +2543,20 @@ public class GamesListDelegate extends ListDelegateBase
}
}
private void setDualpaneAndFinish( boolean enable )
{
XWPrefs.setPrefsBoolean( m_activity, R.string.key_enable_dualpane,
enable );
Intent intent = makeSelfIntent( m_activity );
int bodyID = enable ? R.string.post_dualpane_on_body
: R.string.post_dualpane_off_body;
Utils.postNotification( m_activity, intent,
R.string.post_dualpane_title,
bodyID, R.string.post_dualpane_title );
Utils.showToast( m_activity, R.string.dualpane_restart );
m_activity.finish();
}
public static void boardDestroyed( long rowid )
{
if ( null != s_self ) {

View file

@ -341,6 +341,9 @@ public class PrefsDelegate extends DelegateBase
if ( ABUtils.haveActionBar() ) {
hideOne( R.string.key_hide_title, R.string.prefs_appearance );
}
}
if ( !XWPrefs.getIsTablet( m_activity ) ) {
hideOne( R.string.key_enable_dualpane, R.string.prefs_appearance );
}
}
}