mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-22 07:37:40 +00:00
Language settings screen refinement
This commit is contained in:
parent
4ce013f4d5
commit
2e107825a8
7 changed files with 134 additions and 34 deletions
|
|
@ -845,7 +845,13 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi
|
|||
public void onLexicalModelInstalled(List<Map<String, String>> lexicalModelsInstalled) {
|
||||
for(int i=0; i<lexicalModelsInstalled.size(); i++) {
|
||||
HashMap<String, String>lexicalModelInfo = new HashMap<>(lexicalModelsInstalled.get(i));
|
||||
KMManager.addLexicalModel(this, lexicalModelInfo);
|
||||
try {
|
||||
KMManager.addLexicalModel(this, lexicalModelInfo);
|
||||
} catch (RuntimeException e) {
|
||||
// We error-catch this in case it's called from an AsyncTask;
|
||||
// this may happen when installing a new keyboard given that we attempt
|
||||
// to auto-download an appropriate lexical model to match it.
|
||||
}
|
||||
}
|
||||
|
||||
// It would be nice to register associated lexical model
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ public class KMKeyboardDownloaderActivity extends AppCompatActivity {
|
|||
ret = downloadNonKMPKeyboard(remoteUrl, remoteLexicalModelUrl);
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e(TAG, "Error: " + e);
|
||||
Log.e(TAG, "Error: " + e, e);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
// Lists of installed keyboards and installed lexical models
|
||||
private static ArrayList<HashMap<String, String>> keyboardsList = null;
|
||||
private static ArrayList<HashMap<String, String>> lexicalModelsList = null;
|
||||
private static Dataset storageDataset = null;
|
||||
|
||||
private static boolean checkingUpdates = false;
|
||||
private static int updateCount = 0;
|
||||
|
|
@ -372,6 +373,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
boolean result;
|
||||
keyboardsList = list;
|
||||
result = saveList(context, KMManager.KMFilename_KeyboardsList);
|
||||
notifyKeyboardsUpdate(context);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -385,6 +387,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
boolean result;
|
||||
lexicalModelsList = list;
|
||||
result = saveList(context, KMManager.KMFilename_LexicalModelsList);
|
||||
notifyLexicalModelsUpdate(context);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -448,6 +451,8 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
}
|
||||
}
|
||||
|
||||
notifyKeyboardsUpdate(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -481,6 +486,8 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
}
|
||||
}
|
||||
|
||||
notifyLexicalModelsUpdate(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -495,13 +502,14 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
result = saveList(context, KMManager.KMFilename_KeyboardsList);
|
||||
}
|
||||
|
||||
notifyKeyboardsUpdate(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static void deleteKeyboard(Context context, int position) {
|
||||
int curKbPos = getCurrentKeyboardIndex();
|
||||
boolean result = removeKeyboard(context, position);
|
||||
;
|
||||
|
||||
if (result) {
|
||||
Toast.makeText(context, "Keyboard deleted", Toast.LENGTH_SHORT).show();
|
||||
|
|
@ -511,11 +519,13 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
}
|
||||
if (position == curKbPos && listView != null) {
|
||||
switchKeyboard(0);
|
||||
} else {
|
||||
} else if(listView != null) { // A bit of a hack, since LanguageSettingsActivity calls this method too.
|
||||
curKbPos = getCurrentKeyboardIndex();
|
||||
setSelection(curKbPos);
|
||||
}
|
||||
}
|
||||
|
||||
notifyKeyboardsUpdate(context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -556,6 +566,8 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
result = saveList(context, KMManager.KMFilename_LexicalModelsList);
|
||||
}
|
||||
|
||||
notifyLexicalModelsUpdate(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -574,6 +586,8 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
Toast.makeText(context, "Model deleted", Toast.LENGTH_SHORT).show();
|
||||
KMManager.deregisterLexicalModel(modelID);
|
||||
}
|
||||
|
||||
notifyLexicalModelsUpdate(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -596,6 +610,10 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
}
|
||||
|
||||
public static Dataset getInstalledDataset(Context context) {
|
||||
if(storageDataset != null) {
|
||||
return storageDataset;
|
||||
}
|
||||
|
||||
List<? extends Map<String, String>> kbdMapList = getKeyboardsList(context);
|
||||
List<Keyboard> kbdsList = new ArrayList<>(kbdMapList.size());
|
||||
|
||||
|
|
@ -604,17 +622,51 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
}
|
||||
|
||||
List<? extends Map<String, String>> lexMapList = getLexicalModelsList(context);
|
||||
if(lexMapList == null) {
|
||||
lexMapList = new ArrayList<>(0);
|
||||
}
|
||||
List<LexicalModel> lexList = new ArrayList<>(lexMapList.size());
|
||||
|
||||
for(Map<String, String> map: lexMapList) {
|
||||
lexList.add(new LexicalModel(map));
|
||||
}
|
||||
|
||||
Dataset data = new Dataset(context);
|
||||
data.keyboards.addAll(kbdsList);
|
||||
data.lexicalModels.addAll(lexList);
|
||||
storageDataset = new Dataset(context);
|
||||
storageDataset.keyboards.addAll(kbdsList);
|
||||
storageDataset.lexicalModels.addAll(lexList);
|
||||
|
||||
return data;
|
||||
return storageDataset;
|
||||
}
|
||||
|
||||
// While the two following methods aren't exactly ideal, they should be enough to get the job done
|
||||
// for 12.0 before a more complete refactor of this class is done.
|
||||
protected static void notifyKeyboardsUpdate(Context context) {
|
||||
Dataset storage = getInstalledDataset(context);
|
||||
storage.keyboards.setNotifyOnChange(false);
|
||||
storage.keyboards.clear();
|
||||
|
||||
List<? extends Map<String, String>> mapList = getKeyboardsList(context);
|
||||
List<Keyboard> kbdList = new ArrayList<>(mapList.size());
|
||||
for(Map<String, String> map: mapList) {
|
||||
kbdList.add(new Keyboard(map));
|
||||
}
|
||||
storage.keyboards.addAll(kbdList);
|
||||
storage.keyboards.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
protected static void notifyLexicalModelsUpdate(Context context) {
|
||||
Dataset storage = getInstalledDataset(context);
|
||||
storage.lexicalModels.setNotifyOnChange(false);
|
||||
storage.lexicalModels.clear();
|
||||
|
||||
List<? extends Map<String, String>> mapList = getLexicalModelsList(context);
|
||||
List<LexicalModel> lexList = new ArrayList<>(mapList.size());
|
||||
for(Map<String, String> map: mapList) {
|
||||
lexList.add(new LexicalModel(map));
|
||||
}
|
||||
storage.lexicalModels.addAll(lexList);
|
||||
|
||||
storage.lexicalModels.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
protected static ArrayList<HashMap<String, String>> getKeyboardsList(Context context) {
|
||||
|
|
@ -826,6 +878,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Handle within the new CloudRepository class!
|
||||
private static void checkKeyboardUpdates(final Context context) {
|
||||
new AsyncTask<Void, Integer, Integer>() {
|
||||
private final boolean hasConnection = KMManager.hasConnection(context);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ package com.tavultesoft.kmea;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -16,8 +15,6 @@ import android.view.Window;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
|
@ -33,7 +30,6 @@ import com.tavultesoft.kmea.data.Keyboard;
|
|||
import com.tavultesoft.kmea.data.adapters.NestedAdapter;
|
||||
import com.tavultesoft.kmea.util.MapCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
|
|
@ -126,10 +122,6 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
* imageView.setImageResource(R.drawable.ic_arrow_forward);
|
||||
*/
|
||||
|
||||
// String[] from = new String[]{KMManager.KMKey_KeyboardName, KMManager.KMKey_Icon};
|
||||
// int[] to = new int[]{R.id.text1, R.id.image1};
|
||||
// ListAdapter listAdapter = new KMListAdapter(context, associatedKeyboardList, R.layout.list_row_layout1, from, to);
|
||||
|
||||
listView.setAdapter(adapter);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
|
|
@ -190,6 +182,14 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
FilteredKeyboardsAdapter adapter = ((FilteredKeyboardsAdapter) listView.getAdapter());
|
||||
|
||||
if(adapter != null) {
|
||||
// Despite the fact that updates should have been auto-triggered anyway, it seems that we
|
||||
// need a manual call here for things to happen in a timely fashion.
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -211,13 +211,10 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
// Fully details the building of this Activity's list view items.
|
||||
static private class FilteredKeyboardsAdapter extends NestedAdapter<com.tavultesoft.kmea.data.Keyboard, Dataset.Keyboards, String> {
|
||||
static final int RESOURCE = R.layout.list_row_layout1;
|
||||
private final Context context;
|
||||
|
||||
public FilteredKeyboardsAdapter(@NonNull Context context, final Dataset storage, final String languageCode) {
|
||||
// Goal: to not need a custom filter here, instead relying on LanguageDataset's built-in filters.
|
||||
super(context, RESOURCE, storage.keyboards, storage.keyboardFilter, languageCode);
|
||||
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -160,6 +160,16 @@ public class CloudRepository {
|
|||
JSONObject kbdData = new JSONObject();
|
||||
JSONArray lexData = new JSONArray();
|
||||
|
||||
if(loadKeyboardsFromCache) {
|
||||
kbdData = getCachedJSONObject(getKeyboardCacheFile(context));
|
||||
|
||||
// In case something went wrong with the last cache attempt, which can cause a null return.
|
||||
if(kbdData == null) {
|
||||
kbdData = new JSONObject();
|
||||
loadKeyboardsFromCache = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!loadKeyboardsFromCache) {
|
||||
String deviceType = context.getString(R.string.device_type);
|
||||
if (deviceType.equals("AndroidTablet")) {
|
||||
|
|
@ -174,8 +184,15 @@ public class CloudRepository {
|
|||
|
||||
//cloudQueries[cloudQueryEntries++] = new CloudApiParam(ApiTarget.Keyboards, keyboardURL, JSONType.Object);
|
||||
cloudQueries.add(new CloudApiParam(ApiTarget.Keyboards, keyboardURL, JSONType.Object));
|
||||
} else {
|
||||
kbdData = getCachedJSONObject(getKeyboardCacheFile(context));
|
||||
}
|
||||
|
||||
if(loadLexicalModelsFromCache) {
|
||||
lexData = getCachedJSONArray(getLexicalModelCacheFile(context));
|
||||
|
||||
if(lexData == null) {
|
||||
lexData = new JSONArray();
|
||||
loadLexicalModelsFromCache = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!loadLexicalModelsFromCache) {
|
||||
|
|
@ -184,7 +201,6 @@ public class CloudRepository {
|
|||
// query is ready!
|
||||
String lexicalURL = String.format("%s?q", KMKeyboardDownloaderActivity.kKeymanApiModelURL);
|
||||
|
||||
//cloudQueries[cloudQueryEntries++] = new CloudApiParam(ApiTarget.LexicalModels, lexicalURL, JSONType.Array);
|
||||
cloudQueries.add(new CloudApiParam(ApiTarget.LexicalModels, lexicalURL, JSONType.Array));
|
||||
|
||||
|
||||
|
|
@ -198,8 +214,6 @@ public class CloudRepository {
|
|||
// lexicalURL = lexicalURL.substring(0, lexicalURL.lastIndexOf(','));
|
||||
|
||||
/* do what's possible here, rather than in the Task */
|
||||
} else {
|
||||
lexData = getCachedJSONArray(getLexicalModelCacheFile(context));
|
||||
}
|
||||
|
||||
boolean executeCallbacks = true;
|
||||
|
|
@ -214,7 +228,7 @@ public class CloudRepository {
|
|||
}
|
||||
|
||||
// Reuse any valid parts of the cache.
|
||||
if(kbdData != null || lexData != null) {
|
||||
if(loadKeyboardsFromCache || loadLexicalModelsFromCache) {
|
||||
CloudDownloadReturns jsonData = new CloudDownloadReturns(kbdData, lexData);
|
||||
|
||||
// Call the processor method directly with the cached API data.
|
||||
|
|
@ -651,6 +665,7 @@ public class CloudRepository {
|
|||
}
|
||||
|
||||
public void processCloudReturns(CloudDownloadReturns jsonTuple, boolean executeCallbacks) {
|
||||
// TODO: Need proper offline check again.
|
||||
List<Keyboard> keyboardsArrayList = processKeyboardJSON(jsonTuple.keyboardJSON, false);
|
||||
List<LexicalModel> lexicalModelsArrayList = processLexicalModelJSON(jsonTuple.lexicalModelJSON);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,17 @@ public class Dataset extends ArrayAdapter<Dataset.LanguageDataset> {
|
|||
|
||||
super.add(object);
|
||||
|
||||
getMetadataFor(object); // We can ignore the return; this makes sure the needed object is constructed.
|
||||
LanguageDataset data = getMetadataFor(object); // We can ignore the return; this makes sure the needed object is constructed.
|
||||
|
||||
if(object instanceof Keyboard) {
|
||||
if(!data.keyboards.contains(object)) {
|
||||
data.keyboards.add((Keyboard) object);
|
||||
}
|
||||
} else if(object instanceof LexicalModel) {
|
||||
if(!data.lexicalModels.contains(object)) {
|
||||
data.lexicalModels.add((LexicalModel) object);
|
||||
}
|
||||
}
|
||||
|
||||
if(notify) {
|
||||
Dataset.this.notifyDataSetChanged();
|
||||
|
|
@ -154,6 +164,14 @@ public class Dataset extends ArrayAdapter<Dataset.LanguageDataset> {
|
|||
|
||||
super.remove(object);
|
||||
|
||||
LanguageDataset data = getMetadataFor(object);
|
||||
|
||||
if(object instanceof Keyboard) {
|
||||
data.keyboards.remove(object);
|
||||
} else if(object instanceof LexicalModel) {
|
||||
data.lexicalModels.remove(object);
|
||||
}
|
||||
|
||||
handleLanguageItemRemoval(object);
|
||||
|
||||
if(notify) {
|
||||
|
|
@ -168,12 +186,21 @@ public class Dataset extends ArrayAdapter<Dataset.LanguageDataset> {
|
|||
Dataset.this.setNotifyOnChange(false);
|
||||
}
|
||||
|
||||
List<Type> clearedItems = this.asList();
|
||||
// this.asList returns an unmodifiable reference to the internal list -
|
||||
// but that list itself may be modified by this adapter's functions!
|
||||
List<Type> clearedItems = new ArrayList<>(this.asList());
|
||||
|
||||
super.clear();
|
||||
|
||||
for(Type kbd: clearedItems) {
|
||||
handleLanguageItemRemoval(kbd);
|
||||
for(Type object: clearedItems) {
|
||||
LanguageDataset data = getMetadataFor(object);
|
||||
if(object instanceof Keyboard) {
|
||||
data.keyboards.remove(object);
|
||||
} else if(object instanceof LexicalModel) {
|
||||
data.lexicalModels.remove(object);
|
||||
}
|
||||
|
||||
handleLanguageItemRemoval(object);
|
||||
}
|
||||
|
||||
if(notify) {
|
||||
|
|
@ -195,11 +222,11 @@ public class Dataset extends ArrayAdapter<Dataset.LanguageDataset> {
|
|||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
doNotify = true;
|
||||
super.notifyDataSetChanged();
|
||||
Dataset.this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
void _notifyDataSetChanged() {
|
||||
doNotify = true;
|
||||
super.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
|
@ -292,8 +319,8 @@ public class Dataset extends ArrayAdapter<Dataset.LanguageDataset> {
|
|||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
super.notifyDataSetChanged();
|
||||
keyboards.notifyDataSetChanged();
|
||||
lexicalModels.notifyDataSetChanged();
|
||||
keyboards._notifyDataSetChanged();
|
||||
lexicalModels._notifyDataSetChanged();
|
||||
}
|
||||
|
||||
void _notifyDataSetChanged() {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ public class NestedAdapter<Element, A extends ArrayAdapter<Element> & ListBacked
|
|||
this(context, resource, adapter, new AdapterFilter<Element, A, FilterArg>() {
|
||||
@Override
|
||||
public List<Element> selectFrom(A adapter, FilterArg dummy) {
|
||||
return adapter.asList();
|
||||
// Make sure to duplicate the list so that we don't accidentally try to modify our
|
||||
// wrapped adapter's (unmodifiable) contents.
|
||||
return new ArrayList<>(adapter.asList());
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue