Display "legal phonies" using same code as studylist words

Converted studylist to Kotlin, then made most of it a superclass
from which legal phonies display also inherits
This commit is contained in:
Eric House 2024-04-25 12:18:04 -07:00
parent cb540c23c0
commit 21990ece1c
19 changed files with 777 additions and 597 deletions

View file

@ -65,7 +65,6 @@ public class DlgDelegate {
LAUNCH_AFTER_DEL,
CLEAR_INT_STATS, // debug only
RESTART,
LPS_CLEAR,
// BoardDelegate
UNDO_LAST_ACTION,

View file

@ -1460,11 +1460,6 @@ public class GamesListDelegate extends ListDelegateBase
openWithChecks( rowid, summary );
break;
case LPS_CLEAR:
int nDeleted = XwJNI.dvc_clearLegalPhonies();
Utils.showToast( m_activity, R.string.cleared_lps_fmt, nDeleted );
break;
case BACKUP_DO:
showDialogFragment( DlgID.BACKUP_LOADSTORE );
break;
@ -1826,8 +1821,8 @@ public class GamesListDelegate extends ListDelegateBase
enable = nothingSelected && Utils.isGooglePlayApp( m_activity );
Utils.setItemVisible( menu, R.id.games_menu_rateme, enable );
enable = BuildConfig.NON_RELEASE && XwJNI.dvc_haveLegalPhonies();
Utils.setItemVisible( menu, R.id.games_submenu_legalPhonies, enable );
enable = LegalPhoniesDelegate.haveLegalPhonies(m_activity);
Utils.setItemVisible( menu, R.id.games_menu_legalPhonies, enable );
enable = nothingSelected && XWPrefs.getStudyEnabled( m_activity )
&& 0 < DBUtils.studyListLangs( m_activity ).length;
@ -1921,14 +1916,8 @@ public class GamesListDelegate extends ListDelegateBase
}
break;
case R.id.games_menu_clearLPs:
makeConfirmThenBuilder( Action.LPS_CLEAR,
R.string.confirm_clear_lps )
.show();
break;
case R.id.games_menu_listLPs:
String txt = XwJNI.dvc_listLegalPhonies();
makeOkOnlyBuilder( txt ).show();
case R.id.games_menu_legalPhonies:
LegalPhoniesDelegate.launch( getDelegator() );
break;
case R.id.games_menu_study:

View file

@ -0,0 +1,363 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2024 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.os.Bundle
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import org.eehouse.android.xw4.jni.GameSummary
import java.util.HashMap
abstract class IsoWordsBase(delegator: Delegator, sis: Bundle?,
private val CHECKED_KEY: String )
: ListDelegateBase(delegator, sis, R.layout.studylist, R.menu.studylist),
SelectableItem,
View.OnLongClickListener, View.OnClickListener,
AdapterView.OnItemSelectedListener
{
val m_activity = delegator.getActivity()
var m_pickView: LabeledSpinner? = null
var m_spinner: Spinner? = null
var m_langCodes: Array<Utils.ISOCode>? = null
var m_words: Array<String>? = arrayOf()
val m_checkeds = HashSet<String>()
var m_langPosition: Int = 0
var m_adapter: SLWordsAdapter? = null
private var m_origTitle: String? = null
// Subclasses must override these
abstract fun getData(context: Context): HashMap<Utils.ISOCode, Array<String>>
abstract fun clearWords(isoCode: Utils.ISOCode, words: Array<String> )
abstract fun getTitleID(): Int
override fun init( sis: Bundle? )
{
m_pickView = findViewById( R.id.pick_lang ) as LabeledSpinner
m_spinner = m_pickView?.getSpinner()
getBundledData( sis )
initOrFinish( getArguments() )
}
override fun onPrepareOptionsMenu( menu: Menu): Boolean
{
val nSel = m_checkeds.size
Utils.setItemVisible( menu, R.id.slmenu_copy_sel, 0 < nSel )
Utils.setItemVisible( menu, R.id.slmenu_clear_sel, 0 < nSel )
Utils.setItemVisible( menu, R.id.slmenu_select_all,
m_words!!.size > nSel )
Utils.setItemVisible( menu, R.id.slmenu_deselect_all, 0 < nSel )
val enable = 1 == nSel
if ( enable ) {
val title = getString( R.string.button_lookup_fmt,
getSelWords()!![0] )
menu.findItem( R.id.slmenu_lookup_sel ).setTitle( title )
}
Utils.setItemVisible( menu, R.id.slmenu_lookup_sel, enable )
return true
}
override protected fun handleBackPressed(): Boolean
{
val handled = 0 < m_checkeds.size
if ( handled ) {
clearSels()
}
return handled
}
override fun onOptionsItemSelected( item: MenuItem): Boolean
{
var handled = true
when ( item.getItemId() ) {
R.id.slmenu_copy_sel -> {
makeNotAgainBuilder( R.string.key_na_studycopy,
DlgDelegate.Action.SL_COPY_ACTION,
R.string.not_again_studycopy )
.show()
}
R.id.slmenu_clear_sel -> {
val msg = getQuantityString( R.plurals.confirm_studylist_clear_fmt,
m_checkeds.size, m_checkeds.size )
makeConfirmThenBuilder( DlgDelegate.Action.SL_CLEAR_ACTION, msg ).show()
}
R.id.slmenu_select_all -> {
m_checkeds.addAll( m_words!! )
makeAdapter()
setTitleBar()
}
R.id.slmenu_deselect_all -> clearSels()
R.id.slmenu_lookup_sel -> {
val oneWord = arrayOf( getSelWords()!![0] )
launchLookup( oneWord, m_langCodes!![m_langPosition], true )
}
else -> handled = false
}
return handled
}
override fun onSaveInstanceState( outState: Bundle )
{
outState.putSerializable( CHECKED_KEY, m_checkeds as HashSet )
}
//////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
override fun onPosButton(action: DlgDelegate.Action, vararg params: Any ): Boolean
{
Assert.assertVarargsNotNullNR(params)
var handled = true
when ( action ) {
DlgDelegate.Action.SL_CLEAR_ACTION -> {
var selWords: Array<String>? = getSelWords()
if ( null != selWords ) {
clearWords( m_langCodes!![m_langPosition], selWords )
clearSels()
}
initOrFinish()
}
DlgDelegate.Action.SL_COPY_ACTION -> {
var selWords = getSelWords()
Utils.stringToClip( m_activity, TextUtils.join( "\n", selWords!! ) )
val msg = getQuantityString( R.plurals.paste_done_fmt,
selWords.size, selWords.size )
showToast( msg )
}
else -> {
Log.d( TAG, "not handling: %s", action )
handled = false
}
}
return handled
}
//////////////////////////////////////////////////
// SelectableItem interface
//////////////////////////////////////////////////
override fun itemClicked( clicked: SelectableItem.LongClickHandler,
summary: GameSummary
)
{
m_checkeds.add( (clicked as XWListItem).getText() )
}
override public fun itemToggled( toggled: SelectableItem.LongClickHandler,
selected: Boolean )
{
val word = (toggled as XWListItem).getText()
if ( selected ) {
m_checkeds.add( word )
} else {
m_checkeds.remove( word )
}
setTitleBar()
}
//////////////////////////////////////////////////
// AdapterView.OnItemSelectedListener interface
//////////////////////////////////////////////////
override fun onItemSelected( parent: AdapterView<*>?, view: View,
position: Int, id: Long )
{
m_langPosition = position
m_checkeds.clear()
loadList() // because language has changed
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
//////////////////////////////////////////////////
// View.OnClickListener interface
//////////////////////////////////////////////////
override fun onClick( view: View )
{
val item = view as XWListItem
val words: Array<String> = arrayOf(m_words!![item.getPosition()])
launchLookup( words, m_langCodes!![m_langPosition], true )
}
override fun getSelected( obj: SelectableItem.LongClickHandler ): Boolean
{
return m_checkeds.contains( (obj as XWListItem).getText() )
}
//////////////////////////////////////////////////
// View.OnLongClickListener interface
//////////////////////////////////////////////////
override fun onLongClick( view: View ): Boolean
{
val success = view is SelectableItem.LongClickHandler
if ( success ) {
(view as SelectableItem.LongClickHandler).longClicked()
}
return success
}
private fun initOrFinish( args: Bundle? = null )
{
val data = getData(m_activity)
m_langCodes = data.keys.toTypedArray()
when ( m_langCodes!!.size ) {
0 -> finish()
1 -> {
m_pickView!!.setVisibility( View.GONE )
m_langPosition = 0
loadList()
}
else -> {
var startLang: String? = null
var startIndex = -1
if ( null != args ) {
startLang = args.getString( START_LANG )
}
val siz = m_langCodes!!.size
val myNames = ArrayList<String>()
for ( ii in 0 ..< siz ) {
val isoCode = m_langCodes!![ii]
myNames.add( DictLangCache.getLangNameForISOCode( m_activity,
isoCode ))
if ( isoCode.equals( startLang ) ) {
startIndex = ii
}
}
val adapter = ArrayAdapter<String>( m_activity,
android.R.layout.simple_spinner_item,
myNames )
adapter.setDropDownViewResource( android.R.layout.
simple_spinner_dropdown_item )
m_spinner!!.setAdapter( adapter )
m_spinner!!.setOnItemSelectedListener( this )
if ( -1 != startIndex ) {
m_spinner!!.setSelection( startIndex )
}
}
}
}
private fun getBundledData( sis: Bundle? )
{
if ( null != sis ) {
val checkeds = sis.getSerializable( CHECKED_KEY ) as HashSet<String>
if ( null != checkeds ) {
m_checkeds.clear()
m_checkeds.addAll(checkeds)
}
}
}
private fun clearSels()
{
m_checkeds.clear()
makeAdapter()
setTitleBar()
}
private fun setTitleBar()
{
val nSels = m_checkeds.size
setTitle( if ( 0 == nSels ) {
m_origTitle
} else {
getString( R.string.sel_items_fmt, nSels )
} )
invalidateOptionsMenuIf()
}
private fun getSelWords(): Array<String>?
{
val nSels = m_checkeds.size
var result: Array<String>? = null
if ( nSels == m_words!!.size ) {
result = m_words
} else {
val tmp = m_checkeds
result = tmp!!.toTypedArray()
}
return result
}
protected fun loadList()
{
val isoCode = m_langCodes!![m_langPosition]
val data = getData( m_activity )
m_words = data.get( isoCode )
makeAdapter()
val langName = DictLangCache.getLangNameForISOCode( m_activity, isoCode )
m_origTitle = getString( getTitleID(), langName )
setTitleBar()
}
private fun makeAdapter()
{
m_adapter = SLWordsAdapter()
setListAdapter( m_adapter )
}
inner class SLWordsAdapter() : XWListAdapter(m_words!!.size) {
override fun getView( position: Int, convertView: View?,
parent: ViewGroup? ): View {
val item = XWListItem.inflate( m_activity, this@IsoWordsBase )
item.setPosition( position )
val word = m_words!![position]
item.setText( word )
item.setSelected( m_checkeds.contains( word ) )
item.setOnLongClickListener( this@IsoWordsBase )
item.setOnClickListener( this@IsoWordsBase )
return item
}
}
companion object {
private val TAG = IsoWordsBase::class.java.getSimpleName()
const val START_LANG = "START_LANG"
@JvmStatic
protected fun mkBundle( isoCode: Utils.ISOCode? ): Bundle {
val bundle = Bundle()
if ( null != isoCode ) {
bundle.putString( START_LANG, isoCode.toString() )
}
return bundle
}
}
}

View file

@ -0,0 +1,68 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */ /*
* Copyright 2014 - 2016 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.os.Bundle
import org.eehouse.android.xw4.Utils.ISOCode
import org.eehouse.android.xw4.jni.XwJNI
class LegalPhoniesDelegate(delegator: Delegator, sis: Bundle?) :
IsoWordsBase(delegator, sis, "CHECKED_KEY_LP")
{
companion object {
private val TAG = LegalPhoniesDelegate::class.java.getSimpleName()
@JvmStatic
public fun launch( delegator: Delegator )
{
launch( delegator, null )
}
@JvmStatic
public fun launch( delegator: Delegator, isoCode: Utils.ISOCode? )
= delegator.addFragment( LegalPhoniesFrag.newInstance( delegator ),
mkBundle(isoCode) )
@JvmStatic
public fun haveLegalPhonies(context: Context): Boolean
= !getDataPrv(context).isEmpty()
private fun getDataPrv( context: Context ): HashMap<ISOCode, Array<String>> {
val result = HashMap<ISOCode, Array<String>>()
for ( code in XwJNI.dvc_getLegalPhonyCodes() ) {
val strings = XwJNI.dvc_getLegalPhoniesFor( code )
result.put(code, strings)
}
return result
}
}
override fun getData( context: Context ): HashMap<ISOCode, Array<String>>
= getDataPrv(context)
override fun clearWords( isoCode: ISOCode, words: Array<String> )
{
for ( word in words ) {
XwJNI.dvc_clearLegalPhony(isoCode, word)
}
}
override fun getTitleID(): Int = R.string.legalphonies_title_fmt
}

View file

@ -1,5 +1,4 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */ /*
* Copyright 2014 - 2016 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
@ -17,23 +16,18 @@
* 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
package org.eehouse.android.xw4;
import android.os.Bundle
import android.os.Bundle;
public class StudyListFrag extends XWFragment {
public StudyListFrag() {}
public static XWFragment newInstance( Delegator parent )
{
return new StudyListFrag().setParentName( parent );
internal class LegalPhoniesFrag : XWFragment() {
override fun onCreate(sis: Bundle?) {
super.onCreate(LegalPhoniesDelegate(this, sis), sis, true)
}
@Override
public void onCreate( Bundle sis )
{
super.onCreate( new StudyListDelegate( this, sis ), sis, true );
companion object {
fun newInstance(parent: Delegator?): XWFragment {
return LegalPhoniesFrag().setParentName(parent)
}
}
}

View file

@ -1,430 +0,0 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 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.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.ClipboardManager;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.Utils.ISOCode;
import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.loc.LocUtils;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class StudyListDelegate extends ListDelegateBase
implements OnItemSelectedListener, SelectableItem,
View.OnLongClickListener, View.OnClickListener,
DBUtils.StudyListListener {
private static final String TAG = StudyListDelegate.class.getSimpleName();
protected static final String START_LANG = "START_LANG";
private static final String CHECKED_KEY = "CHECKED_KEY";
private Activity m_activity;
private Spinner m_spinner;
private LabeledSpinner m_pickView;
private ISOCode[] m_langCodes;
private String[] m_words;
private Set<String> m_checkeds;
private int m_langPosition;
private SLWordsAdapter m_adapter;
private String m_origTitle;
protected StudyListDelegate( Delegator delegator, Bundle sis )
{
super( delegator, sis, R.layout.studylist, R.menu.studylist );
m_activity = delegator.getActivity();
}
@Override
protected void init( Bundle sis )
{
m_pickView = (LabeledSpinner)findViewById( R.id.pick_lang );
m_spinner = m_pickView.getSpinner();
m_checkeds = new HashSet<>();
m_words = new String[0];
getBundledData( sis );
initOrFinish( getArguments() );
}
@Override
protected void onResume()
{
super.onResume();
DBUtils.addStudyListChangedListener( this );
}
@Override
protected void onPause()
{
DBUtils.removeStudyListChangedListener( this );
super.onPause();
}
@Override
protected boolean handleBackPressed()
{
boolean handled = 0 < m_checkeds.size();
if ( handled ) {
clearSels();
}
return handled;
}
@Override
public boolean onPrepareOptionsMenu( Menu menu )
{
int nSel = m_checkeds.size();
Utils.setItemVisible( menu, R.id.slmenu_copy_sel, 0 < nSel );
Utils.setItemVisible( menu, R.id.slmenu_clear_sel, 0 < nSel );
Utils.setItemVisible( menu, R.id.slmenu_select_all,
m_words.length > nSel );
Utils.setItemVisible( menu, R.id.slmenu_deselect_all, 0 < nSel );
boolean enable = 1 == nSel;
if ( enable ) {
String title = getString( R.string.button_lookup_fmt,
getSelWords()[0] );
menu.findItem( R.id.slmenu_lookup_sel ).setTitle( title );
}
Utils.setItemVisible( menu, R.id.slmenu_lookup_sel, enable );
return true;
}
@Override
public boolean onOptionsItemSelected( MenuItem item )
{
boolean handled = true;
switch ( item.getItemId() ) {
case R.id.slmenu_copy_sel:
makeNotAgainBuilder( R.string.key_na_studycopy,
Action.SL_COPY_ACTION,
R.string.not_again_studycopy )
.show();
break;
case R.id.slmenu_clear_sel:
String msg = getQuantityString( R.plurals.confirm_studylist_clear_fmt,
m_checkeds.size(), m_checkeds.size() );
makeConfirmThenBuilder( Action.SL_CLEAR_ACTION, msg ).show();
break;
case R.id.slmenu_select_all:
for ( String word : m_words ) {
m_checkeds.add( word );
}
makeAdapter();
setTitleBar();
break;
case R.id.slmenu_deselect_all:
clearSels();
break;
case R.id.slmenu_lookup_sel:
String[] oneWord = new String[]{ getSelWords()[0] };
launchLookup( oneWord, m_langCodes[m_langPosition], true );
break;
default:
handled = false;
}
return handled;
}
@Override
protected void onSaveInstanceState( Bundle outState )
{
outState.putSerializable( CHECKED_KEY, (HashSet)m_checkeds );
}
private void getBundledData( Bundle sis )
{
if ( null != sis ) {
m_checkeds = (HashSet)sis.getSerializable( CHECKED_KEY );
}
}
//////////////////////////////////////////////////
// DBUtils.StudyListListener
//////////////////////////////////////////////////
@Override
public void onWordAdded( String word, ISOCode isoCode )
{
if ( isoCode.equals( m_langCodes[m_langPosition] ) ) {
loadList();
}
}
//////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@Override
public boolean onPosButton( Action action, Object... params )
{
Assert.assertVarargsNotNullNR(params);
boolean handled = true;
switch ( action ) {
case SL_CLEAR_ACTION:
String[] selWords = getSelWords();
if ( selWords.length == m_words.length ) {
selWords = null; // all: easier on DB :-)
}
DBUtils.studyListClear( m_activity, m_langCodes[m_langPosition],
selWords );
initOrFinish( null );
break;
case SL_COPY_ACTION:
selWords = getSelWords();
Utils.stringToClip( m_activity, TextUtils.join( "\n", selWords ) );
String msg = getQuantityString( R.plurals.paste_done_fmt,
selWords.length, selWords.length );
showToast( msg );
break;
default:
Log.d( TAG, "not handling: %s", action );
handled = false;
break;
}
return handled;
}
//////////////////////////////////////////////////
// AdapterView.OnItemSelectedListener interface
//////////////////////////////////////////////////
@Override
public void onItemSelected( AdapterView<?> parent, View view,
int position, long id )
{
m_langPosition = position;
m_checkeds.clear();
loadList(); // because language has changed
}
@Override
public void onNothingSelected( AdapterView<?> parent )
{
}
//////////////////////////////////////////////////
// View.OnLongClickListener interface
//////////////////////////////////////////////////
@Override
public boolean onLongClick( View view )
{
boolean success = view instanceof SelectableItem.LongClickHandler;
if ( success ) {
((SelectableItem.LongClickHandler)view).longClicked();
}
return success;
}
//////////////////////////////////////////////////
// View.OnClickListener interface
//////////////////////////////////////////////////
@Override
public void onClick( View view )
{
XWListItem item = (XWListItem)view;
String[] words = { m_words[item.getPosition()] };
launchLookup( words, m_langCodes[m_langPosition], true );
}
//////////////////////////////////////////////////
// SelectableItem interface
//////////////////////////////////////////////////
@Override
public void itemClicked( SelectableItem.LongClickHandler clicked,
GameSummary summary )
{
m_checkeds.add( ((XWListItem)clicked).getText() );
}
@Override
public void itemToggled( SelectableItem.LongClickHandler toggled,
boolean selected )
{
String word = ((XWListItem)toggled).getText();
if ( selected ) {
m_checkeds.add( word );
} else {
m_checkeds.remove( word );
}
setTitleBar();
}
@Override
public boolean getSelected( SelectableItem.LongClickHandler obj )
{
return m_checkeds.contains( ((XWListItem)obj).getText() );
}
private void loadList()
{
ISOCode isoCode = m_langCodes[m_langPosition];
m_words = DBUtils.studyListWords( m_activity, isoCode );
makeAdapter();
String langName = DictLangCache.getLangNameForISOCode( m_activity, isoCode );
m_origTitle = getString( R.string.studylist_title_fmt,
langName );
setTitleBar();
}
private void makeAdapter()
{
m_adapter = new SLWordsAdapter();
setListAdapter( m_adapter );
}
private void initOrFinish( Bundle args )
{
m_langCodes = DBUtils.studyListLangs( m_activity );
if ( 0 == m_langCodes.length ) {
finish();
} else if ( 1 == m_langCodes.length ) {
m_pickView.setVisibility( View.GONE );
m_langPosition = 0;
loadList();
} else {
String startLang = null;
int startIndex = -1;
if ( null != args ) {
startLang = args.getString( START_LANG );
}
String[] myNames = new String[m_langCodes.length];
for ( int ii = 0; ii < m_langCodes.length; ++ii ) {
ISOCode isoCode = m_langCodes[ii];
myNames[ii] = DictLangCache.getLangNameForISOCode( m_activity, isoCode );
if ( isoCode.equals( startLang ) ) {
startIndex = ii;
}
}
ArrayAdapter<String> adapter = new
ArrayAdapter<String>( m_activity,
android.R.layout.simple_spinner_item,
myNames );
adapter.setDropDownViewResource( android.R.layout.
simple_spinner_dropdown_item );
m_spinner.setAdapter( adapter );
m_spinner.setOnItemSelectedListener( this );
if ( -1 != startIndex ) {
m_spinner.setSelection( startIndex );
}
}
}
private void setTitleBar()
{
String newTitle;
int nSels = m_checkeds.size();
if ( 0 == nSels ) {
newTitle = m_origTitle;
} else {
newTitle = getString( R.string.sel_items_fmt, nSels );
}
setTitle( newTitle );
invalidateOptionsMenuIf();
}
private String[] getSelWords()
{
String[] result;
int nSels = m_checkeds.size();
if ( nSels == m_words.length ) {
result = m_words;
} else {
result = m_checkeds.toArray( new String[nSels] );
}
return result;
}
private void clearSels()
{
m_checkeds.clear();
makeAdapter();
setTitleBar();
}
public static void launch( Delegator delegator )
{
launch( delegator, null );
}
public static void launch( Delegator delegator, ISOCode isoCode )
{
Activity activity = delegator.getActivity();
if ( null == isoCode ) {
Assert.assertTrueNR( 0 < DBUtils.studyListLangs( activity ).length );
} else {
Assert.assertTrueNR( 0 < DBUtils
.studyListWords( activity, isoCode ).length );
}
Bundle bundle = new Bundle();
if ( null != isoCode ) {
bundle.putString( START_LANG, isoCode.toString() );
}
delegator.addFragment( StudyListFrag.newInstance( delegator ),
bundle );
}
private class SLWordsAdapter extends XWListAdapter {
public SLWordsAdapter()
{
super( m_words.length );
}
public View getView( int position, View convertView, ViewGroup parent ){
XWListItem item =
XWListItem.inflate( m_activity, StudyListDelegate.this );
item.setPosition( position );
String word = m_words[position];
item.setText( word );
item.setSelected( m_checkeds.contains( word ) );
item.setOnLongClickListener( StudyListDelegate.this );
item.setOnClickListener( StudyListDelegate.this );
return item;
}
}
}

View file

@ -0,0 +1,99 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 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.os.Bundle
import java.util.HashMap
import org.eehouse.android.xw4.Utils.ISOCode
class StudyListDelegate(delegator: Delegator, sis: Bundle?) :
IsoWordsBase(delegator, sis, "CHECKED_KEY"),
DBUtils.StudyListListener {
companion object {
private val TAG = StudyListDelegate::class.java.getSimpleName()
@JvmStatic
public fun launch( delegator: Delegator )
{
launch( delegator, null )
}
@JvmStatic
public fun launch( delegator: Delegator, isoCode: ISOCode? )
{
val activity = delegator.getActivity()
if ( null == isoCode ) {
Assert.assertTrueNR( 0 < DBUtils.studyListLangs( activity ).size )
} else {
Assert.assertTrueNR( 0 < DBUtils
.studyListWords( activity, isoCode ).size )
}
delegator.addFragment( StudyListFrag.newInstance( delegator ),
mkBundle( isoCode ) )
}
}
override fun onResume()
{
super.onResume()
DBUtils.addStudyListChangedListener( this )
}
override fun onPause()
{
DBUtils.removeStudyListChangedListener( this )
super.onPause()
}
//////////////////////////////////////////////////
// DBUtils.StudyListListener
//////////////////////////////////////////////////
override fun onWordAdded( word: String, isoCode: ISOCode )
{
if ( isoCode.equals( m_langCodes!![m_langPosition] ) ) {
loadList()
}
}
//////////////////////////////////////////////////
// Abstract methods from superclass
//////////////////////////////////////////////////
override fun getData( context: Context ): HashMap<ISOCode, Array<String>> {
val result = HashMap<ISOCode, Array<String>>()
val codes = DBUtils.studyListLangs( m_activity )
for ( code in codes ) {
val words = DBUtils.studyListWords( m_activity, code )
result.put(code, words)
}
return result
}
override fun clearWords( isoCode: ISOCode, words: Array<String> ) {
DBUtils.studyListClear( m_activity, isoCode, words )
}
override fun getTitleID(): Int = R.string.studylist_title_fmt
}

View file

@ -0,0 +1,33 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */ /*
* Copyright 2014 - 2016 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.os.Bundle
class StudyListFrag : XWFragment() {
override fun onCreate(sis: Bundle?) {
super.onCreate(StudyListDelegate(this, sis), sis, true)
}
companion object {
fun newInstance(parent: Delegator?): XWFragment {
return StudyListFrag().setParentName(parent)
}
}
}

View file

@ -36,7 +36,7 @@ import java.util.HashSet;
import java.util.Set;
abstract class XWFragment extends Fragment implements Delegator {
public abstract class XWFragment extends Fragment implements Delegator {
private static final String TAG = XWFragment.class.getSimpleName();
private static final String PARENT_NAME = "PARENT_NAME";
private static final String COMMIT_ID = "COMMIT_ID";

View file

@ -23,6 +23,7 @@ package org.eehouse.android.xw4.jni;
import android.graphics.Rect;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import org.eehouse.android.xw4.Assert;
@ -189,19 +190,27 @@ public class XwJNI {
dvc_onWebSendResult( getJNI().m_ptrGlobals, resultKey, succeeded, result );
}
public static boolean dvc_haveLegalPhonies()
public static ISOCode[] dvc_getLegalPhonyCodes()
{
return dvc_haveLegalPhonies( getJNI().m_ptrGlobals );
ArrayList<String> list = new ArrayList<>();
dvc_getLegalPhonyCodes(getJNI().m_ptrGlobals, list );
ISOCode[] result = new ISOCode[list.size()];
for ( int ii = 0; ii < result.length; ++ii ) {
result[ii] = new ISOCode(list.get(ii));
}
return result;
}
public static String dvc_listLegalPhonies()
public static String[] dvc_getLegalPhoniesFor( ISOCode code )
{
return dvc_listLegalPhonies( getJNI().m_ptrGlobals );
ArrayList<String> list = new ArrayList<>();
dvc_getLegalPhoniesFor( getJNI().m_ptrGlobals, code.toString(), list );
return list.toArray( new String[list.size()] );
}
public static int dvc_clearLegalPhonies()
public static void dvc_clearLegalPhony( ISOCode code, String phony )
{
return dvc_clearLegalPhonies( getJNI().m_ptrGlobals );
dvc_clearLegalPhony( getJNI().m_ptrGlobals, code.toString(), phony );
}
public static boolean hasKnownPlayers()
@ -540,8 +549,8 @@ public class XwJNI {
XP_KEY_LAST
};
public static native boolean board_handleKey( GamePtr gamePtr, XP_Key key,
boolean up, boolean[] handled );
// public static native boolean board_handleKey( GamePtr gamePtr, XP_Key key,
// boolean up, boolean[] handled );
// public static native boolean board_handleKeyDown( XP_Key key,
// boolean[] handled );
// public static native boolean board_handleKeyRepeat( XP_Key key,
@ -833,9 +842,13 @@ public class XwJNI {
private static native void dvc_onWebSendResult( long jniState, int resultKey,
boolean succeeded,
String result );
private static native boolean dvc_haveLegalPhonies( long jniState );
private static native String dvc_listLegalPhonies( long jniState );
private static native int dvc_clearLegalPhonies( long jniState );
private static native void dvc_getLegalPhonyCodes(long jniState,
ArrayList<String> list);
private static native void dvc_getLegalPhoniesFor( long jniState, String code,
ArrayList<String> list );
private static native void
dvc_clearLegalPhony( long jniState, String code, String phony );
private static native String[] kplr_getPlayers( long jniState, boolean byDate );
private static native boolean kplr_renamePlayer( long jniState, String oldName,
String newName );

View file

@ -33,18 +33,9 @@
android:icon="@drawable/dict__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/games_submenu_legalPhonies"
<item android:id="@+id/games_menu_legalPhonies"
android:title="@string/gamel_menu_legalPhonies"
>
<menu>
<item android:id="@+id/games_menu_clearLPs"
android:title="@string/gamel_menu_clearLPs"
/>
<item android:id="@+id/games_menu_listLPs"
android:title="@string/gamel_menu_listLPs"
/>
</menu>
</item>
/>
<item android:id="@+id/games_menu_study"
android:title="@string/gamel_menu_study"

View file

@ -548,7 +548,7 @@
<!-- The third button in the "Phonies found" dialog. Means we'll
accept the phonies AND will record them so they'll be
accepted from now on. -->
<string name="buttonYesAnd">Yes/Save</string>
<string name="buttonYesAnd">Yes &amp; Save</string>
<!--
############################################################

View file

@ -13,10 +13,9 @@
<string name="gamel_menu_clearLPs">Clear all</string>
<string name="gamel_menu_listLPs">Show all</string>
<string name="cleared_lps_fmt">Cleared %1$d legal phonies</string>
<string name="confirm_clear_lps">Are you sure you want to clear
saved “legal phonies”?\n\nThis action cannot be undone.</string>
<string name="legalphonies_title_fmt">Legal phonies for %1$s</string>
</resources>

View file

@ -429,6 +429,16 @@ setIntInArray( JNIEnv* env, jintArray arr, int index, int val )
(*env)->ReleaseIntArrayElements( env, arr, ints, 0 );
}
void
addStrToList( JNIEnv* env, jobject list, const XP_UCHAR* str )
{
jmethodID mid = getMethodID( env, list, "add", "(Ljava/lang/Object;)Z" );
jstring jstr = (*env)->NewStringUTF( env, str );
(*env)->CallBooleanMethod( env, list, mid, jstr );
deleteLocalRef( env, jstr );
}
jobjectArray
makeStringArray( JNIEnv* env, const int count, const XP_UCHAR* const* vals )
{
@ -602,15 +612,15 @@ addrTypesToJ( JNIEnv* env, const CommsAddrRec* addr )
makeObjectEmptyConstr( env, PKG_PATH("jni/CommsAddrRec$CommsConnTypeSet") );
XP_ASSERT( !!result );
jmethodID mid2 = getMethodID( env, result, "add",
jmethodID mid = getMethodID( env, result, "add",
"(Ljava/lang/Object;)Z" );
XP_ASSERT( !!mid2 );
XP_ASSERT( !!mid );
CommsConnType typ;
for ( XP_U32 st = 0; addr_iter( addr, &typ, &st ); ) {
jobject jtyp = intToJEnum( env, typ,
PKG_PATH("jni/CommsAddrRec$CommsConnType") );
XP_ASSERT( !!jtyp );
(*env)->CallBooleanMethod( env, result, mid2, jtyp );
(*env)->CallBooleanMethod( env, result, mid, jtyp );
deleteLocalRef( env, jtyp );
}
return result;

View file

@ -75,6 +75,8 @@ void setIntArray( JNIEnv* env, jobject jowner, const char* ownerField,
int getIntsFromArray( JNIEnv* env, int dest[], jintArray arr, int count, bool del );
void setIntInArray( JNIEnv* env, jintArray arr, int index, int val );
void addStrToList( JNIEnv* env, jobject list, const XP_UCHAR* str );
jbyteArray makeByteArray( JNIEnv* env, int size, const jbyte* vals );
jobjectArray makeByteArrayArray( JNIEnv* env, int siz );

View file

@ -794,48 +794,60 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1onWebSendResult
DVC_HEADER_END();
}
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1haveLegalPhonies
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
typedef struct _CollectState {
JNIEnv* env;
jobject list;
} CollectState;
static void
wordCollector( const XP_UCHAR* str, void* closure )
{
jboolean jresult;
DVC_HEADER(jniGlobalPtr);
jresult = dvc_haveLegalPhonies( globalState->dutil, env );
DVC_HEADER_END();
return jresult;
CollectState* cs = (CollectState*)closure;
addStrToList( cs->env, cs->list, str );
}
#ifdef DEBUG
JNIEXPORT jstring JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1listLegalPhonies
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getLegalPhonyCodes
(JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject list)
{
jstring jresult;
DVC_HEADER(jniGlobalPtr);
#ifdef MEM_DEBUG
MemPoolCtx* mpool = GETMPOOL( globalState );
#endif
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globalState->vtMgr,
NULL, 0, NULL, NULL );
dvc_listLegalPhonies( globalState->dutil, env, stream );
jresult = streamToJString( env, stream );
stream_destroy( stream );
CollectState cs = {
.env = env,
.list = list,
};
dvc_getIsoCodes( globalState->dutil, env, wordCollector, &cs );
DVC_HEADER_END();
return jresult;
}
#endif
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1clearLegalPhonies
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getLegalPhoniesFor
(JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jcode, jobject list)
{
jint result;
DVC_HEADER(jniGlobalPtr);
result = dvc_clearLegalPhonies( globalState->dutil, env );
const char* code = (*env)->GetStringUTFChars( env, jcode, NULL );
CollectState cs = {
.env = env,
.list = list,
};
dvc_getPhoniesFor( globalState->dutil, env, code, wordCollector, &cs );
(*env)->ReleaseStringUTFChars( env, jcode, code );
DVC_HEADER_END();
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1clearLegalPhony
(JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jcode, jstring jphony)
{
DVC_HEADER(jniGlobalPtr);
const char* code = (*env)->GetStringUTFChars( env, jcode, NULL );
const char* phony = (*env)->GetStringUTFChars( env, jphony, NULL );
dvc_clearLegalPhony( globalState->dutil, env, code, phony );
(*env)->ReleaseStringUTFChars( env, jcode, code );
(*env)->ReleaseStringUTFChars( env, jphony, phony );
DVC_HEADER_END();
return result;
}
# ifdef XWFEATURE_KNOWNPLAYERS

View file

@ -722,10 +722,12 @@ dvc_onWebSendResult( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U32 resultKey,
}
}
typedef struct _FindIsoState {
typedef struct _PhoniesMapState {
XW_DUtilCtxt* dutil;
const XP_UCHAR* isoCode;
PhoniesDataCodes* found;
} FindIsoState;
const XP_UCHAR* phony;
const DLHead* found;
} PhoniesMapState;
static ForEachAct
findIsoProc( const DLHead* elem, void* closure )
@ -733,9 +735,9 @@ findIsoProc( const DLHead* elem, void* closure )
ForEachAct result = FEA_OK;
PhoniesDataCodes* pdc = (PhoniesDataCodes*)elem;
FindIsoState* fis = (FindIsoState*)closure;
if ( 0 == XP_STRCMP( fis->isoCode, pdc->isoCode ) ) {
fis->found = pdc;
PhoniesMapState* pms = (PhoniesMapState*)closure;
if ( 0 == XP_STRCMP( pms->isoCode, pdc->isoCode ) ) {
pms->found = elem;
result = FEA_EXIT;
}
return result;
@ -744,11 +746,11 @@ findIsoProc( const DLHead* elem, void* closure )
static PhoniesDataCodes*
findForIso( XW_DUtilCtxt* XP_UNUSED_DBG(dutil), DevCtxt* dc, const XP_UCHAR* isoCode )
{
FindIsoState fis = {
PhoniesMapState ms = {
.isoCode = isoCode,
};
dll_map( &dc->pd->links, findIsoProc, NULL, &fis );
PhoniesDataCodes* pdc = fis.found;
dll_map( &dc->pd->links, findIsoProc, NULL, &ms );
PhoniesDataCodes* pdc = (PhoniesDataCodes*)ms.found;
if ( !pdc ) {
pdc = XP_CALLOC( dutil->mpool, sizeof(*pdc) );
@ -885,19 +887,13 @@ dvc_haveLegalPhonies( XW_DUtilCtxt* dutil, XWEnv xwe )
return result;
}
typedef struct _FreeState {
XW_DUtilCtxt* dutil;
XP_U16 count;
} FreeState;
static void
freeOnePhony( DLHead* elem, void* closure )
{
FreeState* fs = (FreeState*)closure;
++fs->count;
PhoniesMapState* ms = (PhoniesMapState*)closure;
const PhoniesDataStrs* pds = (PhoniesDataStrs*)elem;
XP_FREE( fs->dutil->mpool, pds->phony );
XP_FREE( fs->dutil->mpool, elem );
XP_FREE( ms->dutil->mpool, pds->phony );
XP_FREE( ms->dutil->mpool, elem );
}
static void
@ -908,86 +904,110 @@ freeOneCode( DLHead* elem, void* closure)
dll_removeAll( &pdc->head->links, freeOnePhony, closure );
#ifdef MEM_DEBUG
FreeState* fs = (FreeState*)closure;
PhoniesMapState* ms = (PhoniesMapState*)closure;
#endif
XP_FREE( fs->dutil->mpool, pdc->isoCode );
XP_FREE( fs->dutil->mpool, elem );
XP_FREE( ms->dutil->mpool, pdc->isoCode );
XP_FREE( ms->dutil->mpool, elem );
}
static DevCtxt*
freePhonyState( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U16* lenP )
freePhonyState( XW_DUtilCtxt* dutil, XWEnv xwe )
{
FreeState fs = { .dutil = dutil, };
PhoniesMapState ms = { .dutil = dutil, };
DevCtxt* dc = load( dutil, xwe );
dll_removeAll( &dc->pd->links, freeOneCode, &fs );
if ( !!lenP ) {
*lenP = fs.count;
}
dll_removeAll( &dc->pd->links, freeOneCode, &ms );
dc->pd = NULL;
return dc;
}
XP_U16
dvc_clearLegalPhonies( XW_DUtilCtxt* dutil, XWEnv xwe )
static ForEachAct
clearPhonyProc( const DLHead* elem, void* closure )
{
DevCtxt* dc = load( dutil, xwe );
XP_U16 len = dll_length( &dc->pd->links );
freePhonyState( dutil, xwe, &len );
storePhoniesData( dutil, xwe, dc );
return len;
ForEachAct result = FEA_OK;
const PhoniesDataStrs* pds = (PhoniesDataStrs*)elem;
PhoniesMapState* ms = (PhoniesMapState*)closure;
if ( 0 == XP_STRCMP( ms->phony, pds->phony ) ) {
result = FEA_EXIT | FEA_REMOVE;
}
return result;
}
#ifdef DEBUG
static ForEachAct
listPhoniesProc( const DLHead* elem, void* closure )
void
dvc_clearLegalPhony( XW_DUtilCtxt* dutil, XWEnv xwe,
const XP_UCHAR* isoCode,
const XP_UCHAR* phony )
{
const PhoniesDataStrs* pds = (PhoniesDataStrs*)elem;
XWStreamCtxt* stream = (XWStreamCtxt*)closure;
DevCtxt* dc = load( dutil, xwe );
PhoniesDataCodes* pdc = findForIso( dutil, dc, isoCode );
stream_catString( stream, "- " );
stream_catString( stream, pds->phony );
stream_catString( stream, "\n" );
PhoniesMapState ms = { .dutil = dutil, .phony = phony, };
pdc->head = (PhoniesDataStrs*)
dll_map( &pdc->head->links, clearPhonyProc, freeOnePhony, &ms );
if ( !pdc->head ) {
dc->pd = (PhoniesDataCodes*)dll_remove( &dc->pd->links, &pdc->links );
freeOneCode( &pdc->links, &ms );
}
storePhoniesData( dutil, xwe, dc );
}
typedef struct _GetWordsState {
WordCollector proc;
void* closure;
} GetWordsState;
static ForEachAct
getIsosProc( const DLHead* elem, void* closure )
{
const PhoniesDataCodes* pdc = (PhoniesDataCodes*)elem;
GetWordsState* gws = (GetWordsState*)closure;
(*gws->proc)( pdc->isoCode, gws->closure );
return FEA_OK;
}
static ForEachAct
listIsosProc( const DLHead* elem, void* closure )
getWordsProc( const DLHead* elem, void* closure )
{
const PhoniesDataCodes* pdc = (PhoniesDataCodes*)elem;
XWStreamCtxt* stream = (XWStreamCtxt*)closure;
stream_catString( stream, pdc->isoCode );
stream_catString( stream, ":\n" );
dll_map( &pdc->head->links, listPhoniesProc, NULL, stream );
const PhoniesDataStrs* pds = (PhoniesDataStrs*)elem;
GetWordsState* gws = (GetWordsState*)closure;
(*gws->proc)( pds->phony, gws->closure );
return FEA_OK;
}
void
dvc_listLegalPhonies( XW_DUtilCtxt* dutil, XWEnv xwe, XWStreamCtxt* stream )
dvc_getIsoCodes( XW_DUtilCtxt* dutil, XWEnv xwe,
WordCollector proc, void* closure )
{
DevCtxt* dc = load( dutil, xwe );
dll_map( &dc->pd->links, listIsosProc, NULL, stream );
stream_putU8( stream, '\0' );
}
#endif
GetWordsState gws = {
.proc = proc,
.closure = closure,
};
typedef struct _FindPhonyData {
XP_Bool found;
const XP_UCHAR* isoCode;
const XP_UCHAR* phony;
} FindPhonyData;
DevCtxt* dc = load( dutil, xwe );
dll_map( &dc->pd->links, getIsosProc, NULL, &gws );
}
void
dvc_getPhoniesFor( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* code,
WordCollector proc, void* closure )
{
GetWordsState gws = {
.proc = proc,
.closure = closure,
};
DevCtxt* dc = load( dutil, xwe );
PhoniesDataCodes* pdc = findForIso( dutil, dc, code );
dll_map( &pdc->head->links, getWordsProc, NULL, &gws );
}
static ForEachAct
findPhonyProc2( const DLHead* elem, void* closure )
{
ForEachAct result = FEA_OK;
FindPhonyData* fpd = (FindPhonyData*)closure;
PhoniesMapState* ms = (PhoniesMapState*)closure;
const PhoniesDataStrs* pds = (PhoniesDataStrs*)elem;
if ( 0 == XP_STRCMP( fpd->phony, pds->phony ) ) {
fpd->found = XP_TRUE;
if ( 0 == XP_STRCMP( ms->phony, pds->phony ) ) {
ms->found = elem;
result |= FEA_EXIT;
}
return result;
@ -997,9 +1017,9 @@ static ForEachAct
findPhonyProc1( const DLHead* elem, void* closure )
{
ForEachAct result = FEA_OK;
FindPhonyData* fpd = (FindPhonyData*)closure;
PhoniesMapState* ms = (PhoniesMapState*)closure;
const PhoniesDataCodes* pdc = (PhoniesDataCodes*)elem;
if ( 0 == XP_STRCMP( fpd->isoCode, pdc->isoCode ) ) {
if ( 0 == XP_STRCMP( ms->isoCode, pdc->isoCode ) ) {
dll_map( &pdc->head->links, findPhonyProc2, NULL, closure );
result |= FEA_EXIT;
}
@ -1012,14 +1032,13 @@ dvc_isLegalPhony( XW_DUtilCtxt* dutil, XWEnv xwe,
{
DevCtxt* dc = load( dutil, xwe );
FindPhonyData fpd = {
PhoniesMapState ms = {
.isoCode = isoCode,
.phony = phony,
.found = XP_FALSE,
};
dll_map( &dc->pd->links, findPhonyProc1, NULL, &fpd );
dll_map( &dc->pd->links, findPhonyProc1, NULL, &ms );
return fpd.found;
return NULL != ms.found;
}
static void
@ -1095,7 +1114,7 @@ dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe )
void
dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe )
{
DevCtxt* dc = freePhonyState( dutil, xwe, NULL );
DevCtxt* dc = freePhonyState( dutil, xwe );
pthread_mutex_destroy( &dc->webSendMutex );

View file

@ -68,10 +68,14 @@ void dvc_addLegalPhony( XW_DUtilCtxt* dutil, XWEnv xwe,
XP_Bool dvc_isLegalPhony( XW_DUtilCtxt* dutil, XWEnv xwe,
const XP_UCHAR* isoCode, const XP_UCHAR* phony );
XP_Bool dvc_haveLegalPhonies( XW_DUtilCtxt* dutil, XWEnv xwe );
XP_U16 dvc_clearLegalPhonies( XW_DUtilCtxt* dutil, XWEnv xwe );
#ifdef DEBUG
void dvc_listLegalPhonies( XW_DUtilCtxt* dutil, XWEnv xwe, XWStreamCtxt* stream );
#endif
void dvc_clearLegalPhony( XW_DUtilCtxt* dutil, XWEnv xwe,
const XP_UCHAR* isoCode, const XP_UCHAR* phony );
typedef void (*WordCollector)(const XP_UCHAR* str, void* closure);
void dvc_getIsoCodes( XW_DUtilCtxt* dutil, XWEnv env, WordCollector proc,
void* closure );
void dvc_getPhoniesFor( XW_DUtilCtxt* dutil, XWEnv env, const XP_UCHAR* code,
WordCollector proc, void* closure );
/* All platforms need to call this shortly after setting up their XW_DUtilCtxt */
void dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe );

View file

@ -2508,6 +2508,20 @@ testStreams( LaunchParams* params )
#endif
}
static void
testPhonies( LaunchParams* params )
{
XW_DUtilCtxt* dutil = params->dutil;
dvc_addLegalPhony( dutil, NULL_XWE, "en", "QI" );
dvc_addLegalPhony( dutil, NULL_XWE, "de", "PUTZ" );
XP_ASSERT( dvc_isLegalPhony( dutil, NULL_XWE, "en", "QI" ) );
XP_ASSERT( !dvc_isLegalPhony( dutil, NULL_XWE, "fr", "QI" ) );
XP_ASSERT( !dvc_isLegalPhony( dutil, NULL_XWE, "de", "QI" ) );
XP_ASSERT( dvc_haveLegalPhonies( dutil, NULL_XWE ) );
dvc_clearLegalPhony( dutil, NULL_XWE, "en", "QI" );
XP_ASSERT( !dvc_isLegalPhony( dutil, NULL_XWE, "en", "QI" ) );
}
static void
freeParams( LaunchParams* params )
{
@ -3437,6 +3451,7 @@ main( int argc, char** argv )
mainParams.pDb = gdb_open( mainParams.dbName );
dvc_init( mainParams.dutil, NULL_XWE );
testPhonies( &mainParams );
if ( mainParams.useCurses ) {
/* if ( mainParams.needsNewGame ) { */