preserve checkmarks when invite dialogs rotate

This commit is contained in:
Eric House 2019-04-08 18:46:25 -07:00
parent ec5162ddce
commit 8f77a87a7a
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.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@ -87,12 +88,19 @@ public class BTInviteDelegate extends InviteDelegate {
sort();
}
void remove(final Set<? extends InviterItem> checked)
void remove( final Set<String> checked )
{
for ( InviterItem item : checked ) {
TwoStringPair pair = (TwoStringPair)item;
stamps.remove( pair.str2 );
pairs.remove( pair );
for ( String dev : checked ) {
stamps.remove( dev );
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
protected void init( Bundle savedInstanceState )
{
super.init( savedInstanceState );
String msg = getQuantityString( R.plurals.invite_bt_desc_fmt_2, m_nMissing,
m_nMissing )
+ getString( R.string.invite_bt_desc_postscript );

View file

@ -89,6 +89,7 @@ abstract class InviteDelegate extends DelegateBase
public static final String RAR = "RAR";
private static final String INTENT_KEY_NMISSING = "NMISSING";
protected static final String INTENT_KEY_LASTDEV = "LDEV";
private static final String KEY_CHECKED = "CHECKED";
protected int m_nMissing;
protected String m_lastDev;
@ -97,7 +98,7 @@ abstract class InviteDelegate extends DelegateBase
private LinearLayout m_lv;
private TextView m_ev;
protected Map<InviterItem, Integer> m_counts;
protected Set<InviterItem> m_checked;
private HashSet<String> m_checked;
private boolean m_setChecked;
private boolean m_remotesAreRobots;
@ -127,7 +128,27 @@ abstract class InviteDelegate extends DelegateBase
@Override
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 )
@ -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 );
////////////////////////////////////////
@ -214,10 +228,12 @@ abstract class InviteDelegate extends DelegateBase
{
if ( m_inviteButton == view ) {
int len = m_checked.size();
String[] devs = new String[len];
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];
for ( int ii = 0; ii < len; ++ii ) {
@ -235,10 +251,15 @@ abstract class InviteDelegate extends DelegateBase
private InviterItem[] getSelItems()
{
int ii = 0;
InviterItem[] result = new InviterItem[m_checked.size()];
for ( InviterItem checked : m_checked ) {
result[ii++] = checked;
int next = 0;
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;
}
@ -270,22 +291,25 @@ abstract class InviteDelegate extends DelegateBase
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.
private void updateChecked( List<? extends InviterItem> newItems )
{
Set<InviterItem> old = new HashSet<>();
Set<String> old = new HashSet<>();
old.addAll( m_checked );
m_checked.clear();
for ( Iterator<InviterItem> iter = old.iterator(); iter.hasNext(); ) {
InviterItem oldItem = iter.next();
for ( Iterator<String> iter = old.iterator(); iter.hasNext(); ) {
String oldDev = iter.next();
for ( InviterItem item : newItems ) {
if ( item.equals( oldItem ) ) {
m_checked.add( item );
if ( item.getDev().equals( oldDev ) ) {
m_checked.add( oldDev );
break;
}
}
@ -295,23 +319,23 @@ abstract class InviteDelegate extends DelegateBase
// callbacks made by InviteItemsAdapter
protected void onItemChecked( InviterItem item, boolean checked )
{
String dev = item.getDev();
if ( checked ) {
m_checked.add( item );
m_checked.add( dev );
} else {
m_checked.remove( item );
m_checked.remove( dev );
}
}
private View makeViewFor( int itemID, final InviterItem item )
{
final LinearLayout layout = (LinearLayout)
final InviterItemFrame layout = (InviterItemFrame)
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
FrameLayout frame = (FrameLayout)layout.findViewById( R.id.frame );
View child = inflate( itemID );
frame.addView( child );
((FrameLayout)layout.findViewById( R.id.frame )).addView( child );
onChildAdded( child, item );
m_counts.put( item, 1 );
@ -340,30 +364,28 @@ abstract class InviteDelegate extends DelegateBase
} );
}
box.setOnCheckedChangeListener( new OnCheckedChangeListener() {
layout.setOnCheckedChangeListener( new OnCheckedChangeListener() {
@Override
public void onCheckedChanged( CompoundButton buttonView,
boolean isChecked ) {
if ( !isChecked ) {
m_setChecked = false;
}
if ( isChecked ) {
m_checked.add( item );
} else {
m_checked.remove( item );
}
onItemChecked( item, isChecked );
onItemChecked( item, isChecked );
tryEnable();
}
} );
if ( m_setChecked || m_checked.contains( item ) ) {
box.setChecked( true );
} else if ( null != m_lastDev && m_lastDev.equals(item.getDev()) ) {
String dev = item.getDev();
boolean setIt = false;
if ( m_setChecked || m_checked.contains( dev ) ) {
setIt = true;
} else if ( null != m_lastDev && m_lastDev.equals( dev ) ) {
m_lastDev = null;
box.setChecked( true );
setIt = true;
}
layout.setChecked( setIt );
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 )
{
if ( BuildConfig.RELAYINVITE_SUPPORTED ) {
super.init( savedInstanceState );
String msg = getString( R.string.button_invite );
msg = getQuantityString( R.plurals.invite_relay_desc_fmt, m_nMissing,
m_nMissing, msg );
@ -470,11 +472,12 @@ public class RelayInviteDelegate extends InviteDelegate {
private void getSavedState()
{
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>();
} else {
m_devIDRecs = (ArrayList<DevIDRec>)Utils
.string64ToSerializable( dataString );
}
}
@ -500,23 +503,14 @@ public class RelayInviteDelegate extends InviteDelegate {
private void clearSelectedImpl()
{
Set<InviterItem> checked = getChecked();
Iterator<DevIDRec> iter = m_devIDRecs.iterator();
for ( ; iter.hasNext(); ) {
if ( checked.contains( iter.next() ) ) {
Set<String> checked = getChecked();
for ( Iterator<DevIDRec> iter = m_devIDRecs.iterator(); iter.hasNext(); ) {
if ( checked.contains( iter.next().getDev() ) ) {
iter.remove();
}
}
clearChecked();
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 {

View file

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

View file

@ -60,6 +60,8 @@ public class WiDirInviteDelegate extends InviteDelegate
@Override
protected void init( Bundle savedInstanceState )
{
super.init( savedInstanceState );
String msg = getString( R.string.button_invite );
msg = getQuantityString( R.plurals.invite_p2p_desc_fmt, m_nMissing,
m_nMissing, msg );
@ -94,15 +96,6 @@ public class WiDirInviteDelegate extends InviteDelegate
((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
public void setChanged( Map<String, String> macToName )
{

View file

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