mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-13 04:09:25 +00:00
Initial use of new CloudRepository class.
This commit is contained in:
parent
3166cfa876
commit
fb30e0ffa0
3 changed files with 237 additions and 116 deletions
|
|
@ -22,7 +22,9 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.tavultesoft.kmea.data.CloudRepository;
|
||||
import com.tavultesoft.kmea.data.Dataset;
|
||||
import com.tavultesoft.kmea.data.LexicalModel;
|
||||
import com.tavultesoft.kmea.data.adapters.LexicalModelsAdapter;
|
||||
import com.tavultesoft.kmea.packages.JSONUtils;
|
||||
import com.tavultesoft.kmea.util.FileUtils;
|
||||
|
|
@ -43,6 +45,8 @@ import java.util.ArrayList;
|
|||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Keyman Settings --> Languages Settings --> Language Settings --> Model List
|
||||
|
|
@ -57,6 +61,7 @@ public final class ModelPickerActivity extends AppCompatActivity {
|
|||
|
||||
// Merged array list of lexical models to display in ListView
|
||||
private static ArrayList<HashMap<String, String>> lexicalModelsArrayList = null;
|
||||
private static Dataset repo;
|
||||
private static Dataset.LexicalModels lexicalModelsAdapter = null;
|
||||
private boolean didExecuteParser = false;
|
||||
|
||||
|
|
@ -110,12 +115,110 @@ public final class ModelPickerActivity extends AppCompatActivity {
|
|||
listView.setFastScrollEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
Log.d(TAG, "Exiting ModelPickerActivity");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (!didExecuteParser) {
|
||||
didExecuteParser = true;
|
||||
new JSONParse().execute();
|
||||
//new JSONParse().execute();
|
||||
repo = CloudRepository.shared.fetchDataset(context, new Runnable() {
|
||||
public void run() {
|
||||
|
||||
List<Map<String, String>> mapList = new ArrayList<>();
|
||||
for(LexicalModel model: repo.lexicalModels.asList()) {
|
||||
mapList.add(model.map);
|
||||
}
|
||||
|
||||
String[] from = new String[]{"leftIcon", KMManager.KMKey_LexicalModelName, KMManager.KMKey_Icon};
|
||||
int[] to = new int[]{R.id.image1, R.id.text1, R.id.image2};
|
||||
|
||||
ListAdapter adapter = new KMListAdapter(context, mapList,
|
||||
R.layout.models_list_row_layout, from, to);
|
||||
listView.setAdapter(adapter);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
|
||||
selectedIndex = position;
|
||||
HashMap<String, String> modelInfo = lexicalModelsArrayList.get(position);
|
||||
String packageID = modelInfo.get(KMManager.KMKey_PackageID);
|
||||
String languageID = modelInfo.get(KMManager.KMKey_LanguageID);
|
||||
String modelID = modelInfo.get(KMManager.KMKey_LexicalModelID);
|
||||
String modelName = modelInfo.get(KMManager.KMKey_LexicalModelName);
|
||||
String langName = modelInfo.get(KMManager.KMKey_LanguageName);
|
||||
|
||||
// File check to see if lexical model already exists locally
|
||||
File modelCheck = new File(KMManager.getLexicalModelsDir() + packageID + File.separator + modelID + ".model.js");
|
||||
|
||||
// Using the presence of the left icon "check" to determine if the model is installed
|
||||
boolean modelInstalled = modelInfo.containsKey("leftIcon");
|
||||
if (modelInstalled) {
|
||||
// Show Model Info
|
||||
listView.setItemChecked(position, true);
|
||||
listView.setSelection(position);
|
||||
|
||||
// Start intent for selected Predictive Text Model screen
|
||||
if (!languageID.equalsIgnoreCase(modelInfo.get(KMManager.KMKey_LanguageID))) {
|
||||
Log.d(TAG, "Language ID " + languageID + " doesn't match model language ID: " +
|
||||
modelInfo.get(KMManager.KMKey_LanguageID));
|
||||
}
|
||||
Bundle bundle = new Bundle();
|
||||
// Note: package ID of a model is different from package ID for a keyboard.
|
||||
// Language ID can be re-used
|
||||
bundle.putString(KMManager.KMKey_PackageID, packageID);
|
||||
bundle.putString(KMManager.KMKey_LanguageID, languageID);
|
||||
bundle.putString(KMManager.KMKey_LexicalModelID, modelID);
|
||||
bundle.putString(KMManager.KMKey_LexicalModelName, modelName);
|
||||
bundle.putString(KMManager.KMKey_LexicalModelVersion,
|
||||
modelInfo.get(KMManager.KMKey_LexicalModelVersion));
|
||||
bundle.putString(KMManager.KMKey_CustomModel,
|
||||
MapCompat.getOrDefault(modelInfo, KMManager.KMKey_CustomModel, "N"));
|
||||
Intent i = new Intent(context, ModelInfoActivity.class);
|
||||
i.putExtras(bundle);
|
||||
startActivityForResult(i, 1);
|
||||
} else if (modelCheck.exists()) {
|
||||
// Handle scenario where previously installed kmp already exists so
|
||||
// we only need to add the model to the list of installed models
|
||||
// Add help link
|
||||
modelInfo.put(KMManager.KMKey_CustomHelpLink, "");
|
||||
boolean result = KMManager.addLexicalModel(context, modelInfo);
|
||||
if (result) {
|
||||
Toast.makeText(context, "Model installed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
// Don't register associated lexical model because this is not a UI view
|
||||
} else {
|
||||
// Model isn't installed so prompt to download it
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_PKG_ID, packageID);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_LANG_ID, languageID);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_MODEL_ID, modelID);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_MODEL_NAME, modelName);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_LANG_NAME, langName);
|
||||
args.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_CUSTOM, false);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_MODEL_URL,
|
||||
modelInfo.get(KMManager.KMKey_LexicalModelPackageFilename));
|
||||
Intent i = new Intent(getApplicationContext(), KMKeyboardDownloaderActivity.class);
|
||||
i.putExtras(args);
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Intent i = getIntent();
|
||||
listView.setSelectionFromTop(i.getIntExtra("listPosition", 0),
|
||||
i.getIntExtra("offsetY", 0));
|
||||
}
|
||||
}, new Runnable() {
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tavultesoft.kmea.data.adapters;
|
||||
package com.tavultesoft.kmea.data;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
|
|
@ -16,8 +16,6 @@ import com.tavultesoft.kmea.KMKeyboardDownloaderActivity;
|
|||
import com.tavultesoft.kmea.KMManager;
|
||||
import com.tavultesoft.kmea.KeyboardPickerActivity;
|
||||
import com.tavultesoft.kmea.R;
|
||||
import com.tavultesoft.kmea.data.Dataset;
|
||||
import com.tavultesoft.kmea.data.LexicalModel;
|
||||
import com.tavultesoft.kmea.packages.JSONUtils;
|
||||
import com.tavultesoft.kmea.util.FileUtils;
|
||||
|
||||
|
|
@ -67,20 +65,33 @@ public class CloudRepository {
|
|||
* @param onFinish A callback to run immediately upon successful completion of the download.
|
||||
* @return A Dataset object implementing the Adapter interface to be asynchronously filled.
|
||||
*/
|
||||
public Dataset fetchDataset(@NonNull Context context, Runnable onFinish) {
|
||||
public Dataset fetchDataset(@NonNull Context context, Runnable onSuccess, Runnable onFailure) {
|
||||
Dataset dataset = new Dataset(context);
|
||||
|
||||
// Get kmp.json info from installed models.
|
||||
JSONArray kmpLexicalModelsArray = JSONUtils.getLexicalModels();
|
||||
|
||||
if (kmpLexicalModelsArray.length() == 0) {
|
||||
// May need to note this for handling a 'failure' check.
|
||||
} else {
|
||||
dataset.lexicalModels.addAll(processLexicalModelJSON(kmpLexicalModelsArray, context));
|
||||
}
|
||||
|
||||
boolean loadFromCache = this.shouldUseCache(context, getLexicalModelCacheFile(context));
|
||||
|
||||
if(!loadFromCache) {
|
||||
CloudDownloadTask downloadTask = new CloudDownloadTask(context, onFinish);
|
||||
CloudDownloadTask downloadTask = new CloudDownloadTask(context, dataset, onSuccess, onFailure);
|
||||
|
||||
String lexicalURL = String.format("%s?q", KMKeyboardDownloaderActivity.kKeymanApiModelURL);
|
||||
|
||||
/* do what's possible here, rather than in the Task */
|
||||
|
||||
downloadTask.execute("" /* use actual URLs here */);
|
||||
downloadTask.execute(lexicalURL);
|
||||
} else {
|
||||
// just load from the cache.
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
return dataset;
|
||||
}
|
||||
|
||||
protected File getLexicalModelCacheFile(Context context) {
|
||||
|
|
@ -105,6 +116,78 @@ public class CloudRepository {
|
|||
return lmData;
|
||||
}
|
||||
|
||||
protected List<LexicalModel> processLexicalModelJSON(JSONArray models, Context context) {
|
||||
List<LexicalModel> modelList = new ArrayList<>(models.length());
|
||||
|
||||
try {
|
||||
// Parse the model JSON Object from the merged list of api.keyman.com query and available kmp's.
|
||||
// Known assumption:
|
||||
// 2. query is built on a single language ID so the "languages" array will only have one language
|
||||
int modelsLength = models.length();
|
||||
for (int i = 0; i < modelsLength; i++) {
|
||||
JSONObject model = models.getJSONObject(i);
|
||||
String packageID = "", modelURL = "";
|
||||
if (model.has(KMManager.KMKey_PackageID)) {
|
||||
packageID = model.getString(KMManager.KMKey_PackageID);
|
||||
} else {
|
||||
// Determine package ID from packageFilename
|
||||
modelURL = model.optString("packageFilename", "");
|
||||
packageID = FileUtils.getFilename(modelURL);
|
||||
packageID = packageID.replace(".model.kmp", "");
|
||||
}
|
||||
|
||||
// api.keyman.com query returns an array of language IDs Strings while
|
||||
// kmp.json "languages" is an array of JSONObject
|
||||
String languageID = "", langName = "";
|
||||
Object obj = model.getJSONArray("languages");
|
||||
if (((JSONArray) obj).get(0) instanceof String) {
|
||||
// language name not provided, so re-use language ID
|
||||
languageID = model.getJSONArray("languages").getString(0);
|
||||
langName = languageID;
|
||||
} else if (((JSONArray) obj).get(0) instanceof JSONObject) {
|
||||
JSONObject languageObj = model.getJSONArray("languages").getJSONObject(0);
|
||||
languageID = languageObj.getString("id");
|
||||
langName = languageObj.getString("name");
|
||||
}
|
||||
|
||||
String modelID = model.getString("id");
|
||||
String modelName = model.getString("name");
|
||||
String modelVersion = model.getString("version");
|
||||
|
||||
String isCustom = model.optString("CustomModel", "N");
|
||||
String icon = "0";
|
||||
|
||||
HashMap<String, String> hashMap = new HashMap<String, String>();
|
||||
hashMap.put(KMManager.KMKey_PackageID, packageID);
|
||||
hashMap.put(KMManager.KMKey_LanguageID, languageID);
|
||||
hashMap.put(KMManager.KMKey_LexicalModelID, modelID);
|
||||
hashMap.put(KMManager.KMKey_LexicalModelName, modelName);
|
||||
hashMap.put(KMManager.KMKey_LanguageName, langName);
|
||||
hashMap.put(KMManager.KMKey_LexicalModelVersion, modelVersion);
|
||||
hashMap.put(KMManager.KMKey_CustomModel, isCustom);
|
||||
hashMap.put("isEnabled", "true");
|
||||
hashMap.put(KMManager.KMKey_Icon, String.valueOf(R.drawable.ic_arrow_forward));
|
||||
|
||||
// TODO: (Move to PickerActivity) Display check for installed models
|
||||
String modelKey = String.format("%s_%s_%s", packageID, languageID, modelID);
|
||||
if (KeyboardPickerActivity.containsLexicalModel(context, modelKey)) { // FIXME:
|
||||
hashMap.put("leftIcon", String.valueOf(R.drawable.ic_check));
|
||||
} else {
|
||||
// Otherwise, include link to .kmp file
|
||||
hashMap.put(KMManager.KMKey_LexicalModelPackageFilename, modelURL);
|
||||
}
|
||||
// TODO: (Move section) END.
|
||||
|
||||
modelList.add(new LexicalModel(hashMap));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e("JSONParse", "Error: " + e);
|
||||
return new ArrayList<>(); // Is this ideal?
|
||||
}
|
||||
|
||||
return modelList;
|
||||
}
|
||||
|
||||
private class CloudApiReturns {
|
||||
public final JSONArray keyboardJSON;
|
||||
public final JSONArray lexicalModelJSON;
|
||||
|
|
@ -124,21 +207,26 @@ public class CloudRepository {
|
|||
private final String iconKey = "icon";
|
||||
|
||||
private final Context context;
|
||||
private final Runnable finish;
|
||||
private final Runnable success;
|
||||
private final Runnable failure;
|
||||
|
||||
public CloudDownloadTask(Context context, Runnable finish) {
|
||||
private final Dataset dataset;
|
||||
|
||||
public CloudDownloadTask(Context context, Dataset dataset, Runnable success, Runnable failure) {
|
||||
this.context = context;
|
||||
this.dataset = dataset;
|
||||
this.hasConnection = KMManager.hasConnection(context);
|
||||
|
||||
if(finish == null) {
|
||||
finish = new Runnable() {
|
||||
if(failure == null) {
|
||||
failure = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
}
|
||||
this.finish = finish;
|
||||
this.success = success;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
protected void showProgressDialog(final Runnable finishCallback) {
|
||||
|
|
@ -179,7 +267,7 @@ public class CloudRepository {
|
|||
showProgressDialog(new Runnable() {
|
||||
@Override
|
||||
public void run() { // runs on 'cancel' selection.
|
||||
finish.run();
|
||||
failure.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -191,6 +279,11 @@ public class CloudRepository {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Facilitates debugging the AsyncTask.
|
||||
if(android.os.Debug.isDebuggerConnected()) {
|
||||
android.os.Debug.waitForDebugger();
|
||||
}
|
||||
|
||||
int count = urls.length;
|
||||
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
|
|
@ -199,9 +292,12 @@ public class CloudRepository {
|
|||
lmData = getCachedJSONArray(context, getLexicalModelCacheFile(context));
|
||||
} else if (hasConnection) {
|
||||
try {
|
||||
String remoteUrl = String.format("%s?q=bcp47:%s", KMKeyboardDownloaderActivity.kKeymanApiModelURL);
|
||||
String remoteUrl = urls[0];
|
||||
lmData = jsonParser.getJSONObjectFromUrl(remoteUrl, JSONArray.class);
|
||||
Log.d(TAG, "JSON retrieved!");
|
||||
Log.d(TAG, lmData.toString());
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
lmData = null;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -215,112 +311,25 @@ public class CloudRepository {
|
|||
// Clear pre-existing list
|
||||
List<LexicalModel> lexicalModelsArrayList = new ArrayList<>();
|
||||
|
||||
// TODO: This part should be utilized to init the lexical model array before the Cloud returns.
|
||||
// Consolidate kmp.json info from models.
|
||||
JSONArray kmpLexicalModelsArray = JSONUtils.getLexicalModels();
|
||||
|
||||
// TODO: Should this be handled here? Probably split instead - the lexicalJSON check is valid,
|
||||
// but the kmpLexicalModelsArray check goes with pre-init.
|
||||
if (lexicalJSON == null && kmpLexicalModelsArray.length() == 0) {
|
||||
if (lexicalJSON == null && dataset.isEmpty()) {
|
||||
Toast.makeText(context, "Failed to access Keyman server!", Toast.LENGTH_SHORT).show();
|
||||
finish.run();
|
||||
failure.run();
|
||||
return null;
|
||||
}
|
||||
// TODO: End "should this be handled?" section.
|
||||
|
||||
try {
|
||||
JSONArray models;
|
||||
if (!hasConnection) {
|
||||
// When offline, only use keyboards available from kmp.json
|
||||
models = kmpLexicalModelsArray;
|
||||
} else {
|
||||
// Otherwise, merge kmpLexicalModelsArray with cloud jsonArray
|
||||
models = (lexicalJSON != null) ? lexicalJSON : new JSONArray(); // Start with cloud model list.
|
||||
for (int i = 0; i < kmpLexicalModelsArray.length(); i++) { // Iterate over local KMPs.
|
||||
JSONObject kmpLexicalModel = kmpLexicalModelsArray.getJSONObject(i);
|
||||
String kmpModelID = kmpLexicalModel.getString("id");
|
||||
|
||||
int modelIndex = JSONUtils.findID(models, kmpModelID);
|
||||
if (modelIndex == -1) {
|
||||
// Lexical model from KMP didn't exist in cloud so add new entry
|
||||
models.put(kmpLexicalModel);
|
||||
} else {
|
||||
// Lexical model already installed from local kmp so replace models entry
|
||||
models.put(modelIndex, kmpLexicalModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (models == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse the model JSON Object from the merged list of api.keyman.com query and available kmp's.
|
||||
// Known assumption:
|
||||
// 2. query is built on a single language ID so the "languages" array will only have one language
|
||||
int modelsLength = models.length();
|
||||
for (int i = 0; i < modelsLength; i++) {
|
||||
JSONObject model = models.getJSONObject(i);
|
||||
String packageID = "", modelURL = "";
|
||||
if (model.has(KMManager.KMKey_PackageID)) {
|
||||
packageID = model.getString(KMManager.KMKey_PackageID);
|
||||
} else {
|
||||
// Determine package ID from packageFilename
|
||||
modelURL = model.optString("packageFilename", "");
|
||||
packageID = FileUtils.getFilename(modelURL);
|
||||
packageID = packageID.replace(".model.kmp", "");
|
||||
}
|
||||
|
||||
// api.keyman.com query returns an array of language IDs Strings while
|
||||
// kmp.json "languages" is an array of JSONObject
|
||||
String languageID = "", langName = "";
|
||||
Object obj = model.getJSONArray("languages");
|
||||
if (((JSONArray) obj).get(0) instanceof String) {
|
||||
// language name not provided, so re-use language ID
|
||||
languageID = model.getJSONArray("languages").getString(0);
|
||||
langName = languageID;
|
||||
} else if (((JSONArray) obj).get(0) instanceof JSONObject) {
|
||||
JSONObject languageObj = model.getJSONArray("languages").getJSONObject(0);
|
||||
languageID = languageObj.getString("id");
|
||||
langName = languageObj.getString("name");
|
||||
}
|
||||
|
||||
String modelID = model.getString("id");
|
||||
String modelName = model.getString("name");
|
||||
String modelVersion = model.getString("version");
|
||||
|
||||
String isCustom = model.optString("CustomModel", "N");
|
||||
String icon = "0";
|
||||
|
||||
HashMap<String, String> hashMap = new HashMap<String, String>();
|
||||
hashMap.put(KMManager.KMKey_PackageID, packageID);
|
||||
hashMap.put(KMManager.KMKey_LanguageID, languageID);
|
||||
hashMap.put(KMManager.KMKey_LexicalModelID, modelID);
|
||||
hashMap.put(KMManager.KMKey_LexicalModelName, modelName);
|
||||
hashMap.put(KMManager.KMKey_LanguageName, langName);
|
||||
hashMap.put(KMManager.KMKey_LexicalModelVersion, modelVersion);
|
||||
hashMap.put(KMManager.KMKey_CustomModel, isCustom);
|
||||
hashMap.put("isEnabled", "true");
|
||||
hashMap.put(KMManager.KMKey_Icon, String.valueOf(R.drawable.ic_arrow_forward));
|
||||
|
||||
// TODO: (Move to PickerActivity) Display check for installed models
|
||||
String modelKey = String.format("%s_%s_%s", packageID, languageID, modelID);
|
||||
if (KeyboardPickerActivity.containsLexicalModel(context, modelKey)) { // FIXME:
|
||||
hashMap.put("leftIcon", String.valueOf(R.drawable.ic_check));
|
||||
} else {
|
||||
// Otherwise, include link to .kmp file
|
||||
hashMap.put(KMManager.KMKey_LexicalModelPackageFilename, modelURL);
|
||||
}
|
||||
// TODO: (Move section) END.
|
||||
|
||||
lexicalModelsArrayList.add(new LexicalModel(hashMap));
|
||||
}
|
||||
|
||||
return lexicalModelsArrayList;
|
||||
} catch (JSONException e) {
|
||||
Log.e("JSONParse", "Error: " + e);
|
||||
return null; // Is this ideal?
|
||||
if (!hasConnection) {
|
||||
// When offline, only use keyboards available from kmp.json
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// Otherwise, merge kmpLexicalModelsArray with cloud jsonArray
|
||||
JSONArray models = (lexicalJSON != null) ? lexicalJSON : new JSONArray(); // Start with cloud model list.
|
||||
|
||||
if (models == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return processLexicalModelJSON(models, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -335,8 +344,16 @@ public class CloudRepository {
|
|||
}
|
||||
|
||||
List<LexicalModel> lexicalModelsArrayList = processLexicalModels(jsonArray.lexicalModelJSON);
|
||||
// TODO: Filter out any duplicates from already-installed models!
|
||||
for(LexicalModel model: lexicalModelsArrayList) {
|
||||
// TODO: Check for duplicates / possible updates!
|
||||
//if(dataset.lexicalModels.____) // if the model's already in the list, do a thing.
|
||||
}
|
||||
|
||||
// TODO: Set the CloudRepository's LexicalModelsAdapter to have the same members.
|
||||
|
||||
// And finish.
|
||||
success.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -137,6 +137,7 @@ public class Dataset extends ArrayAdapter<LanguageDataset> {
|
|||
public Dataset(@NonNull Context context) {
|
||||
super(context, 0, new ArrayList<LanguageDataset>());
|
||||
|
||||
this.context = context.getApplicationContext();
|
||||
keyboards = new Keyboards(context);
|
||||
lexicalModels = new LexicalModels(context);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue