preserve checkmarks when invite dialogs rotate

This commit is contained in:
Eric House 2019-04-08 18:46:25 -07:00
parent 6a28e398dc
commit 6098f28210
7 changed files with 157 additions and 77 deletions

View file

@ -41,6 +41,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -87,12 +88,19 @@ public class BTInviteDelegate extends InviteDelegate {
sort(); sort();
} }
void remove(final Set<? extends InviterItem> checked) void remove( final Set<String> checked )
{ {
for ( InviterItem item : checked ) { for ( String dev : checked ) {
TwoStringPair pair = (TwoStringPair)item; stamps.remove( dev );
stamps.remove( pair.str2 );
pairs.remove( pair ); for ( Iterator<TwoStringPair> iter = pairs.iterator();
iter.hasNext(); ) {
TwoStringPair pair = iter.next();
if ( pair.str2.equals( dev ) ) {
iter.remove();
break;
}
}
} }
} }
@ -137,6 +145,8 @@ public class BTInviteDelegate extends InviteDelegate {
@Override @Override
protected void init( Bundle savedInstanceState ) protected void init( Bundle savedInstanceState )
{ {
super.init( savedInstanceState );
String msg = getQuantityString( R.plurals.invite_bt_desc_fmt_2, m_nMissing, String msg = getQuantityString( R.plurals.invite_bt_desc_fmt_2, m_nMissing,
m_nMissing ) m_nMissing )
+ getString( R.string.invite_bt_desc_postscript ); + getString( R.string.invite_bt_desc_postscript );

View file

@ -89,6 +89,7 @@ abstract class InviteDelegate extends DelegateBase
public static final String RAR = "RAR"; public static final String RAR = "RAR";
private static final String INTENT_KEY_NMISSING = "NMISSING"; private static final String INTENT_KEY_NMISSING = "NMISSING";
protected static final String INTENT_KEY_LASTDEV = "LDEV"; protected static final String INTENT_KEY_LASTDEV = "LDEV";
private static final String KEY_CHECKED = "CHECKED";
protected int m_nMissing; protected int m_nMissing;
protected String m_lastDev; protected String m_lastDev;
@ -97,7 +98,7 @@ abstract class InviteDelegate extends DelegateBase
private LinearLayout m_lv; private LinearLayout m_lv;
private TextView m_ev; private TextView m_ev;
protected Map<InviterItem, Integer> m_counts; protected Map<InviterItem, Integer> m_counts;
protected Set<InviterItem> m_checked; private HashSet<String> m_checked;
private boolean m_setChecked; private boolean m_setChecked;
private boolean m_remotesAreRobots; private boolean m_remotesAreRobots;
@ -127,7 +128,27 @@ abstract class InviteDelegate extends DelegateBase
@Override @Override
protected void init( Bundle sis ) protected void init( Bundle sis )
{ {
super.init( sis ); // DO NOT CALL super!!!
getBundledData( sis );
}
@Override
protected void onSaveInstanceState( Bundle outState )
{
addBundledData( outState );
super.onSaveInstanceState( outState );
}
private void getBundledData( Bundle bundle )
{
if ( null != bundle ) {
m_checked = (HashSet<String>)bundle.getSerializable( KEY_CHECKED );
}
}
private void addBundledData( Bundle bundle )
{
bundle.putSerializable( KEY_CHECKED, m_checked );
} }
protected void init( String descTxt, int emptyMsgId ) protected void init( String descTxt, int emptyMsgId )
@ -198,13 +219,6 @@ abstract class InviteDelegate extends DelegateBase
} }
} }
protected void listSelected( InviterItem[] selected, String[] devs )
{
for ( int ii = 0; ii < selected.length; ++ii ) {
devs[ii] = selected[ii].getDev();
}
}
abstract void onBarButtonClicked( int id ); abstract void onBarButtonClicked( int id );
//////////////////////////////////////// ////////////////////////////////////////
@ -214,10 +228,12 @@ abstract class InviteDelegate extends DelegateBase
{ {
if ( m_inviteButton == view ) { if ( m_inviteButton == view ) {
int len = m_checked.size(); int len = m_checked.size();
String[] devs = new String[len];
InviterItem[] items = getSelItems(); InviterItem[] items = getSelItems();
listSelected( items, devs ); String[] devs = new String[items.length];
for ( int ii = 0; ii < items.length; ++ii ) {
devs[ii] = items[ii].getDev();
}
int[] counts = new int[len]; int[] counts = new int[len];
for ( int ii = 0; ii < len; ++ii ) { for ( int ii = 0; ii < len; ++ii ) {
@ -235,10 +251,15 @@ abstract class InviteDelegate extends DelegateBase
private InviterItem[] getSelItems() private InviterItem[] getSelItems()
{ {
int ii = 0;
InviterItem[] result = new InviterItem[m_checked.size()]; InviterItem[] result = new InviterItem[m_checked.size()];
for ( InviterItem checked : m_checked ) { int next = 0;
result[ii++] = checked; for ( int ii = 0; ii < m_lv.getChildCount(); ++ii ) {
InviterItemFrame child = (InviterItemFrame)m_lv.getChildAt( ii );
InviterItem item = child.getItem();
if ( m_checked.contains( item.getDev() ) ) {
result[next++] = item;
Assert.assertTrue( child.isChecked() || !BuildConfig.DEBUG );
}
} }
return result; return result;
} }
@ -270,22 +291,25 @@ abstract class InviteDelegate extends DelegateBase
m_inviteButton.setEnabled( count > 0 && count <= m_nMissing ); m_inviteButton.setEnabled( count > 0 && count <= m_nMissing );
} }
final Set<InviterItem> getChecked() { return m_checked; } final Set<String> getChecked() { return m_checked; }
protected void clearChecked() { m_checked.clear(); } protected void clearChecked()
{
m_checked.clear();
}
// Figure which previously-checked items belong in the new set. // Figure which previously-checked items belong in the new set.
private void updateChecked( List<? extends InviterItem> newItems ) private void updateChecked( List<? extends InviterItem> newItems )
{ {
Set<InviterItem> old = new HashSet<>(); Set<String> old = new HashSet<>();
old.addAll( m_checked ); old.addAll( m_checked );
m_checked.clear(); m_checked.clear();
for ( Iterator<InviterItem> iter = old.iterator(); iter.hasNext(); ) { for ( Iterator<String> iter = old.iterator(); iter.hasNext(); ) {
InviterItem oldItem = iter.next(); String oldDev = iter.next();
for ( InviterItem item : newItems ) { for ( InviterItem item : newItems ) {
if ( item.equals( oldItem ) ) { if ( item.getDev().equals( oldDev ) ) {
m_checked.add( item ); m_checked.add( oldDev );
break; break;
} }
} }
@ -295,23 +319,23 @@ abstract class InviteDelegate extends DelegateBase
// callbacks made by InviteItemsAdapter // callbacks made by InviteItemsAdapter
protected void onItemChecked( InviterItem item, boolean checked ) protected void onItemChecked( InviterItem item, boolean checked )
{ {
String dev = item.getDev();
if ( checked ) { if ( checked ) {
m_checked.add( item ); m_checked.add( dev );
} else { } else {
m_checked.remove( item ); m_checked.remove( dev );
} }
} }
private View makeViewFor( int itemID, final InviterItem item ) private View makeViewFor( int itemID, final InviterItem item )
{ {
final LinearLayout layout = (LinearLayout) final InviterItemFrame layout = (InviterItemFrame)
inflate( R.layout.inviter_item_frame ); inflate( R.layout.inviter_item_frame );
CheckBox box = (CheckBox)layout.findViewById( R.id.inviter_check ); layout.setItem( item );
// Give subclass a chance to install and populate its view // Give subclass a chance to install and populate its view
FrameLayout frame = (FrameLayout)layout.findViewById( R.id.frame );
View child = inflate( itemID ); View child = inflate( itemID );
frame.addView( child ); ((FrameLayout)layout.findViewById( R.id.frame )).addView( child );
onChildAdded( child, item ); onChildAdded( child, item );
m_counts.put( item, 1 ); m_counts.put( item, 1 );
@ -340,30 +364,28 @@ abstract class InviteDelegate extends DelegateBase
} ); } );
} }
box.setOnCheckedChangeListener( new OnCheckedChangeListener() { layout.setOnCheckedChangeListener( new OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged( CompoundButton buttonView, public void onCheckedChanged( CompoundButton buttonView,
boolean isChecked ) { boolean isChecked ) {
if ( !isChecked ) { if ( !isChecked ) {
m_setChecked = false; m_setChecked = false;
} }
if ( isChecked ) {
m_checked.add( item );
} else {
m_checked.remove( item );
}
onItemChecked( item, isChecked );
onItemChecked( item, isChecked );
tryEnable(); tryEnable();
} }
} ); } );
if ( m_setChecked || m_checked.contains( item ) ) { String dev = item.getDev();
box.setChecked( true ); boolean setIt = false;
} else if ( null != m_lastDev && m_lastDev.equals(item.getDev()) ) { if ( m_setChecked || m_checked.contains( dev ) ) {
setIt = true;
} else if ( null != m_lastDev && m_lastDev.equals( dev ) ) {
m_lastDev = null; m_lastDev = null;
box.setChecked( true ); setIt = true;
} }
layout.setChecked( setIt );
return layout; return layout;
} }

View file

@ -0,0 +1,57 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2009-2014 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.CheckBox;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import org.eehouse.android.xw4.InviteDelegate.InviterItem;
public class InviterItemFrame extends LinearLayout /*implements InviterItem*/ {
private InviterItem mItem;
public InviterItemFrame( Context context, AttributeSet as ) {
super( context, as );
}
void setItem( InviterItem item ) { mItem = item; }
InviterItem getItem() { return mItem; }
void setOnCheckedChangeListener( OnCheckedChangeListener listener )
{
((CheckBox)findViewById( R.id.inviter_check ))
.setOnCheckedChangeListener( listener );
}
void setChecked( boolean newVal )
{
((CheckBox)findViewById( R.id.inviter_check ))
.setChecked( newVal );
}
boolean isChecked()
{
return ((CheckBox)findViewById( R.id.inviter_check )).isChecked();
}
}

View file

@ -95,6 +95,8 @@ public class RelayInviteDelegate extends InviteDelegate {
protected void init( Bundle savedInstanceState ) protected void init( Bundle savedInstanceState )
{ {
if ( BuildConfig.RELAYINVITE_SUPPORTED ) { if ( BuildConfig.RELAYINVITE_SUPPORTED ) {
super.init( savedInstanceState );
String msg = getString( R.string.button_invite ); String msg = getString( R.string.button_invite );
msg = getQuantityString( R.plurals.invite_relay_desc_fmt, m_nMissing, msg = getQuantityString( R.plurals.invite_relay_desc_fmt, m_nMissing,
m_nMissing, msg ); m_nMissing, msg );
@ -470,11 +472,12 @@ public class RelayInviteDelegate extends InviteDelegate {
private void getSavedState() private void getSavedState()
{ {
String dataString = DBUtils.getStringFor( m_activity, RECS_KEY, null ); String dataString = DBUtils.getStringFor( m_activity, RECS_KEY, null );
if ( null == dataString ) { if ( null != dataString ) {
m_devIDRecs = (ArrayList<DevIDRec>)Utils.string64ToSerializable( dataString );
}
if ( null == m_devIDRecs ) {
m_devIDRecs = new ArrayList<DevIDRec>(); m_devIDRecs = new ArrayList<DevIDRec>();
} else {
m_devIDRecs = (ArrayList<DevIDRec>)Utils
.string64ToSerializable( dataString );
} }
} }
@ -500,23 +503,14 @@ public class RelayInviteDelegate extends InviteDelegate {
private void clearSelectedImpl() private void clearSelectedImpl()
{ {
Set<InviterItem> checked = getChecked(); Set<String> checked = getChecked();
Iterator<DevIDRec> iter = m_devIDRecs.iterator(); for ( Iterator<DevIDRec> iter = m_devIDRecs.iterator(); iter.hasNext(); ) {
for ( ; iter.hasNext(); ) { if ( checked.contains( iter.next().getDev() ) ) {
if ( checked.contains( iter.next() ) ) {
iter.remove(); iter.remove();
} }
} }
clearChecked(); clearChecked();
saveAndRebuild(); saveAndRebuild();
// int count = m_adapter.getCount();
// for ( int ii = count - 1; ii >= 0; --ii ) {
// if ( m_devIDRecs.get( ii ).m_isChecked ) {
// m_devIDRecs.remove( ii );
// }
// }
// saveAndRebuild();
} }
private static class DevIDRec implements InviterItem, Serializable { private static class DevIDRec implements InviterItem, Serializable {

View file

@ -89,11 +89,13 @@ public class SMSInviteDelegate extends InviteDelegate {
@Override @Override
protected void init( Bundle savedInstanceState ) protected void init( Bundle savedInstanceState )
{ {
super.init( savedInstanceState );
mMeans = InviteMeans.values()[getIntent().getIntExtra(INTENT_KEY_MEANS, -1)]; mMeans = InviteMeans.values()[getIntent().getIntExtra(INTENT_KEY_MEANS, -1)];
String msg = getString( R.string.button_invite ); String msg = getString( R.string.button_invite );
msg = getQuantityString( R.plurals.invite_sms_desc_fmt, m_nMissing, msg = getQuantityString( R.plurals.invite_sms_desc_fmt, m_nMissing,
m_nMissing, msg ); m_nMissing, msg );
super.init( msg, R.string.empty_sms_inviter ); init( msg, R.string.empty_sms_inviter );
addButtonBar( R.layout.sms_buttons, BUTTONIDS ); addButtonBar( R.layout.sms_buttons, BUTTONIDS );
getSavedState(); getSavedState();
@ -338,10 +340,10 @@ public class SMSInviteDelegate extends InviteDelegate {
private void clearSelectedImpl() private void clearSelectedImpl()
{ {
Set<InviterItem> checked = getChecked(); Set<String> checked = getChecked();
Iterator<PhoneRec> iter = m_phoneRecs.iterator(); Iterator<PhoneRec> iter = m_phoneRecs.iterator();
for ( ; iter.hasNext(); ) { for ( ; iter.hasNext(); ) {
if ( checked.contains( iter.next() ) ) { if ( checked.contains( iter.next().getDev() ) ) {
iter.remove(); iter.remove();
} }
} }

View file

@ -60,6 +60,8 @@ public class WiDirInviteDelegate extends InviteDelegate
@Override @Override
protected void init( Bundle savedInstanceState ) protected void init( Bundle savedInstanceState )
{ {
super.init( savedInstanceState );
String msg = getString( R.string.button_invite ); String msg = getString( R.string.button_invite );
msg = getQuantityString( R.plurals.invite_p2p_desc_fmt, m_nMissing, msg = getQuantityString( R.plurals.invite_p2p_desc_fmt, m_nMissing,
m_nMissing, msg ); m_nMissing, msg );
@ -94,15 +96,6 @@ public class WiDirInviteDelegate extends InviteDelegate
((TwoStrsItem)child).setStrings( pair.str2, pair.getDev() ); ((TwoStrsItem)child).setStrings( pair.str2, pair.getDev() );
} }
@Override
protected void listSelected( InviterItem[] selected, String[] devs )
{
for ( int ii = 0; ii < selected.length; ++ii ) {
TwoStringPair pair = (TwoStringPair)selected[ii];
devs[ii] = pair.getDev();
}
}
// DevSetListener interface // DevSetListener interface
public void setChanged( Map<String, String> macToName ) public void setChanged( Map<String, String> macToName )
{ {

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <org.eehouse.android.xw4.InviterItemFrame
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -9,6 +10,7 @@
<CheckBox android:id="@+id/inviter_check" <CheckBox android:id="@+id/inviter_check"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:saveEnabled="false"
/> />
<Spinner android:id="@+id/nperdev_spinner" <Spinner android:id="@+id/nperdev_spinner"
@ -25,4 +27,4 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
/> />
</LinearLayout> </org.eehouse.android.xw4.InviterItemFrame>