add invite history and ability to invite all at once

If inviting known players to a more-than-two-player game, can select all
at once. Required using checkboxes instead of radiobuttons for the case
where nMissing > 1.
This commit is contained in:
Eric House 2020-11-21 15:11:59 -08:00
parent 210b0bcbcb
commit d5be06413f
12 changed files with 231 additions and 58 deletions

View file

@ -682,7 +682,8 @@ public class BoardDelegate extends DelegateBase
private void showInviteChoicesThen()
{
NetLaunchInfo nli = nliForMe();
showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION, nli );
showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION, nli,
m_mySIS.nMissing );
}
@Override
@ -1111,8 +1112,13 @@ public class BoardDelegate extends DelegateBase
break;
case LAUNCH_INVITE_ACTION:
CommsAddrRec addr = (CommsAddrRec)params[0];
tryOtherInvites( addr );
for ( Object obj : params ) {
if ( obj instanceof CommsAddrRec ) {
tryOtherInvites( (CommsAddrRec)obj );
} else {
break;
}
}
break;
case ENABLE_NBS_DO:
@ -1510,6 +1516,23 @@ public class BoardDelegate extends DelegateBase
callInviteChoices();
}
@Override
public void onInfoClicked()
{
SentInvitesInfo sentInfo = DBUtils.getInvitesFor( m_activity, m_rowid );
String msg = sentInfo.getAsText( m_activity );
makeOkOnlyBuilder( msg )
.setTitle( R.string.title_invite_history )
.setAction( Action.INVITE_INFO )
.show();
}
@Override
public long getRowID()
{
return m_rowid;
}
private byte[] getInvite()
{
byte[] result = null;

View file

@ -595,10 +595,10 @@ public abstract class DelegateBase implements DlgClickNotify,
m_dlgDelegate.launchLookup( words, lang, !studyOn );
}
protected void showInviteChoicesThen( Action action,
NetLaunchInfo nli )
protected void showInviteChoicesThen( Action action, NetLaunchInfo nli,
int nMissing )
{
m_dlgDelegate.showInviteChoicesThen( action, nli );
m_dlgDelegate.showInviteChoicesThen( action, nli, nMissing );
}
public Builder makeOkOnlyBuilder( int msgID )

View file

@ -401,11 +401,11 @@ public class DlgDelegate {
}
public void showInviteChoicesThen( final Action action,
NetLaunchInfo nli )
NetLaunchInfo nli, int nMissing )
{
DlgState state = new DlgState( DlgID.INVITE_CHOICES_THEN )
.setAction( action )
.setParams( nli );
.setParams( nli, nMissing );
m_dlgt.show( state );
}

View file

@ -84,10 +84,14 @@ public class InviteChoicesAlert extends DlgDelegateAlert
InviteMeans lastMeans = null;
NetLaunchInfo nli = null;
Object[] params = state.getParams();
int nMissing = 0;
if ( null != params ) {
if ( 0 < params.length && params[0] instanceof NetLaunchInfo ) {
nli = (NetLaunchInfo)params[0];
}
if ( 1 < params.length && params[1] instanceof Integer ) {
nMissing = (Integer)params[1];
}
}
means.add( InviteMeans.EMAIL );
means.add( InviteMeans.SMS_USER );
@ -130,11 +134,15 @@ public class InviteChoicesAlert extends DlgDelegateAlert
InviteMeans means = (InviteMeans)choice;
activity.inviteChoiceMade( state.m_action,
means, state.getParams() );
} else if ( choice instanceof String ) {
String player = (String)choice;
} else if ( choice instanceof String[] ) {
String[] players = (String[])choice;
Object[] params = new Object[players.length];
for ( int ii = 0; ii < params.length; ++ii ) {
String player = players[ii];
CommsAddrRec addr = XwJNI.kplr_getAddr( player );
params[ii] = addr;
}
XWActivity xwact = (XWActivity)context;
Object[] params = { addr };
xwact.onPosButton( state.m_action, params );
} else {
Assert.failDbg();
@ -151,7 +159,7 @@ public class InviteChoicesAlert extends DlgDelegateAlert
;
String[] players = XwJNI.kplr_getPlayers();
mInviteView.setChoices( means, lastSelMeans, players )
mInviteView.setChoices( means, lastSelMeans, players, nMissing )
.setNli( nli )
.setCallbacks( this )
;

View file

@ -59,10 +59,9 @@ public class InviteView extends ScrollView
private ItemClicked mProcs;
private boolean mIsWho;
private RadioGroup mGroupTab;
private RadioGroup mGroupWho;
private LimSelGroup mGroupWho;
private RadioGroup mGroupHow;
private Map<RadioButton, InviteMeans> mHowMeans = new HashMap<>();
private Map<RadioButton, String> mWhoPlayers = new HashMap<>();
private boolean mExpanded = false;
private NetLaunchInfo mNli;
@ -71,7 +70,7 @@ public class InviteView extends ScrollView
}
public InviteView setChoices( List<InviteMeans> meansList, int sel,
String[] players )
String[] players, int maxPlayers )
{
final Context context = getContext();
@ -104,15 +103,10 @@ public class InviteView extends ScrollView
}
if ( haveWho ) {
mGroupWho = (RadioGroup)findViewById( R.id.group_who );
mGroupWho.setOnCheckedChangeListener( this );
for ( String player : players ) {
RadioButton button = (RadioButton)LocUtils
.inflate( context, R.layout.invite_radio );
button.setText( player );
mGroupWho.addView( button );
mWhoPlayers.put( button, player );
}
mGroupWho = ((LimSelGroup)findViewById( R.id.group_who ))
.setLimit( maxPlayers )
.addPlayers( players )
;
}
mIsWho = false; // start with how
showWhoOrHow();
@ -139,20 +133,22 @@ public class InviteView extends ScrollView
return this;
}
public InviteView setCallbacks( ItemClicked procs ) {
public InviteView setCallbacks( ItemClicked procs )
{
mProcs = procs;
mGroupWho.setCallbacks( procs );
return this;
}
public Object getChoice()
{
Object result = null;
RadioButton checked = getCurCheckedFor();
if ( null != checked ) {
if ( mIsWho ) {
result = mWhoPlayers.get(checked);
result = mGroupWho.getSelected();
} else {
result = mHowMeans.get(checked);
int curSel = mGroupHow.getCheckedRadioButtonId();
if ( 0 <= curSel ) {
result = (RadioButton)findViewById(curSel);
}
}
return result;
@ -187,17 +183,6 @@ public class InviteView extends ScrollView
.setVisibility( show ? View.VISIBLE: View.GONE );
}
private RadioButton getCurCheckedFor()
{
RadioButton result = null;
RadioGroup group = mIsWho ? mGroupWho : mGroupHow;
int curSel = group.getCheckedRadioButtonId();
if ( 0 <= curSel ) {
result = (RadioButton)findViewById(curSel);
}
return result;
}
private void showWhoOrHow()
{
if ( null != mGroupWho ) {
@ -205,7 +190,7 @@ public class InviteView extends ScrollView
}
mGroupHow.setVisibility( mIsWho ? View.INVISIBLE : View.VISIBLE );
boolean showEmpty = mIsWho && 0 == mWhoPlayers.size();
boolean showEmpty = mIsWho && 0 == mGroupWho.getChildCount();
findViewById( R.id.who_empty )
.setVisibility( showEmpty ? View.VISIBLE : View.INVISIBLE );
}

View file

@ -28,6 +28,7 @@ import android.content.DialogInterface;
import java.io.Serializable;
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.Perms23.Perm;
import org.eehouse.android.xw4.loc.LocUtils;
@ -57,12 +58,14 @@ class InvitesNeededAlert {
interface Callbacks {
DelegateBase getDelegate();
long getRowID();
void onCloseClicked();
void onInviteClicked();
void onInfoClicked();
}
static void showOrHide( Callbacks callbacks, int nDevsSeen, int nPlayersMissing,
boolean isRematch )
static void showOrHide( Callbacks callbacks, int nDevsSeen,
int nPlayersMissing, boolean isRematch )
{
DbgUtils.assertOnUIThread();
InvitesNeededAlert self = sInstance[0];
@ -102,8 +105,8 @@ class InvitesNeededAlert {
}
}
private static void makeNew( Callbacks callbacks,
int nDevsSeen, int nPlayersMissing, boolean isRematch )
private static void makeNew( Callbacks callbacks, int nDevsSeen,
int nPlayersMissing, boolean isRematch )
{
Log.d( TAG, "makeNew(nDevsSeen=%d, nPlayersMissing=%d)", nDevsSeen, nPlayersMissing );
State state = new State( nDevsSeen, nPlayersMissing, isRematch );
@ -174,6 +177,22 @@ class InvitesNeededAlert {
}
} );
if ( BuildConfig.NON_RELEASE ) {
long rowid = mCallbacks.getRowID();
SentInvitesInfo sentInfo = DBUtils.getInvitesFor( context, rowid );
int nSent = sentInfo.getMinPlayerCount();
boolean invitesSent = nSent >= state.nPlayersMissing;
if ( invitesSent ) {
alert.setNoDismissListenerNeut( ab, R.string.newgame_invite_more,
new OnClickListener() {
@Override
public void onClick( DialogInterface dlg, int item ) {
onNeutClick();
}
} );
}
}
alert.setNoDismissListenerNeg( ab, R.string.button_close,
new OnClickListener() {
@Override
@ -191,6 +210,11 @@ class InvitesNeededAlert {
mCallbacks.onInviteClicked();
}
private void onNeutClick()
{
mCallbacks.onInfoClicked();
}
private void onNegClick()
{
Log.d( TAG, "onNegClick()" );

View file

@ -0,0 +1,120 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2020 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eehouse.android.xw4.loc.LocUtils;
public class LimSelGroup extends LinearLayout
implements OnCheckedChangeListener {
private static final String TAG = LimSelGroup.class.getSimpleName();
private int mLimit;
private InviteView.ItemClicked mProcs;
public LimSelGroup( Context context, AttributeSet as )
{
super( context, as );
}
LimSelGroup setLimit( int limit )
{
Assert.assertTrueNR( 0 < limit );
mLimit = limit;
return this;
}
void setCallbacks( InviteView.ItemClicked procs )
{
mProcs = procs;
}
String[] getSelected()
{
String[] result = null;
int len = mChecked.size();
if ( 0 < len ) {
result = new String[mChecked.size()];
for ( int ii = 0; ii < result.length; ++ii ) {
result[ii] = mChecked.get(ii).getText().toString();
}
}
return result;
}
LimSelGroup addPlayers( String[] names )
{
Context context = getContext();
for ( String name : names ) {
CompoundButton button;
if ( 1 == mLimit ) {
button = (RadioButton)LocUtils.inflate( context, R.layout.invite_radio );
} else {
button = (CheckBox)LocUtils.inflate( context, R.layout.invite_checkbox );
}
button.setText( name );
button.setOnCheckedChangeListener( this );
addView( button );
}
return this;
}
@Override
public void onCheckedChanged( CompoundButton buttonView, boolean isChecked )
{
Log.d( TAG, "onCheckedChanged(%s, %b)", buttonView, isChecked );
addToSet( buttonView, isChecked );
if ( null != mProcs ) {
mProcs.checkButton();
}
}
ArrayList<CompoundButton> mChecked = new ArrayList<>();
private void addToSet( CompoundButton button, boolean nowChecked )
{
for ( Iterator<CompoundButton> iter = mChecked.iterator();
iter.hasNext(); ) {
CompoundButton but = iter.next();
if ( nowChecked ) {
Assert.assertTrueNR( ! but.equals(button) );
} else if ( but.equals(button) ) {
iter.remove();
}
}
if ( nowChecked ) {
mChecked.add( button );
while ( mLimit < mChecked.size() ) {
CompoundButton oldButton = mChecked.remove( 0 );
oldButton.setChecked( false );
}
}
}
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/invite_who_elem"
/>

View file

@ -1,9 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="22dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
style="@style/invite_who_elem"
/>

View file

@ -44,9 +44,11 @@
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RadioGroup android:id="@+id/group_who"
<org.eehouse.android.xw4.LimSelGroup
android:id="@+id/group_who"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
/>
<RadioGroup android:id="@+id/group_how"

View file

@ -1025,7 +1025,8 @@
<string name="newgame_invite">Invite now</string>
<!-- Button offering to invite Known Player to a new game -->
<string name="invite_player_fmt">Invite %1$s</string>
<string name="newgame_invite_more">More info</string>
<string name="newgame_invite_more">History</string>
<string name="title_invite_history">Invitations Sent</string>
<string name="newgame_drop_relay">Drop Relay</string>
<!-- EXPLAIN ME -->

View file

@ -166,4 +166,12 @@
<item name="android:layout_weight">1</item>
<item name="android:drawSelectorOnTop">true</item>
</style>
<style name="invite_who_elem">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:textSize">22dp</item>
<item name="android:paddingTop">5dp</item>
<item name="android:paddingBottom">5dp</item>
</style>
</resources>