diff --git a/app/src/main/java/com/fieldbook/tracker/activities/CollectActivity.java b/app/src/main/java/com/fieldbook/tracker/activities/CollectActivity.java index 4e6800ed4..01b194f1c 100644 --- a/app/src/main/java/com/fieldbook/tracker/activities/CollectActivity.java +++ b/app/src/main/java/com/fieldbook/tracker/activities/CollectActivity.java @@ -7,7 +7,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; -import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -43,10 +42,9 @@ import com.fieldbook.tracker.adapters.InfoBarAdapter; import com.fieldbook.tracker.brapi.model.Observation; import com.fieldbook.tracker.database.DataHelper; -import com.fieldbook.tracker.database.dao.ObservationUnitDao; -import com.fieldbook.tracker.database.dao.StudyDao; import com.fieldbook.tracker.database.models.ObservationModel; import com.fieldbook.tracker.database.models.ObservationUnitModel; +import com.fieldbook.tracker.interfaces.FieldSwitcher; import com.fieldbook.tracker.objects.FieldObject; import com.fieldbook.tracker.objects.GeoNavHelper; import com.fieldbook.tracker.objects.InfoBarModel; @@ -59,9 +57,11 @@ import com.fieldbook.tracker.traits.LayoutCollections; import com.fieldbook.tracker.traits.PhotoTraitLayout; import com.fieldbook.tracker.utilities.CategoryJsonUtil; +import com.fieldbook.tracker.utilities.FieldSwitchImpl; import com.fieldbook.tracker.utilities.InfoBarHelper; import com.fieldbook.tracker.utilities.LocationCollectorUtil; import com.fieldbook.tracker.utilities.SnackbarUtils; +import com.fieldbook.tracker.utilities.SoundHelperImpl; import com.fieldbook.tracker.utilities.TapTargetUtil; import com.fieldbook.tracker.utilities.Utils; import com.fieldbook.tracker.views.CollectInputView; @@ -126,6 +126,11 @@ public class CollectActivity extends ThemedActivity @Inject InfoBarHelper infoBarHelper; + @Inject + FieldSwitchImpl fieldSwitcher; + + @Inject + SoundHelperImpl soundHelper; public static boolean searchReload; public static String searchRange; public static String searchPlot; @@ -260,18 +265,11 @@ public void handleMessage(Message msg) { checkForInitialBarcodeSearch(); } - private void switchField(int studyId, String fieldName, @Nullable String obsUnitId) { + private void switchField(int studyId, @Nullable String obsUnitId) { try { - //updates obs. range view in database - database.switchField(studyId); - - FieldObject fo = database.getFieldObject(studyId); - - ep.edit().putString(GeneralKeys.UNIQUE_NAME, fo.getUnique_id()).apply(); - ep.edit().putString(GeneralKeys.PRIMARY_NAME, fo.getPrimary_id()).apply(); - ep.edit().putString(GeneralKeys.SECONDARY_NAME, fo.getSecondary_id()).apply(); + fieldSwitcher.switchField(studyId); rangeBox.setAllRangeID(); int[] rangeID = rangeBox.getRangeID(); @@ -289,11 +287,7 @@ private void switchField(int studyId, String fieldName, @Nullable String obsUnit moveToSearch("id", rangeID, null, null, obsUnitId, -1); } - //update selected item in field adapter using preference - ep.edit().putString(GeneralKeys.FIELD_FILE, fieldName).apply(); - ep.edit().putInt(GeneralKeys.SELECTED_FIELD_ID, studyId).apply(); - - playSound("hero_simple_celebration"); + soundHelper.playCelebrate(); } catch (Exception e) { @@ -337,7 +331,7 @@ private void checkForInitialBarcodeSearch() { if (fo != null && fo.getExp_name() != null) { - switchField(model.getStudy_id(), fo.getExp_name(), barcode); + switchField(model.getStudy_id(), barcode); } } @@ -477,22 +471,6 @@ public void refreshMain() { refreshLock(); } - @Override - public void playSound(String sound) { - try { - int resID = getResources().getIdentifier(sound, "raw", getPackageName()); - MediaPlayer chimePlayer = MediaPlayer.create(CollectActivity.this, resID); - chimePlayer.start(); - - chimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - public void onCompletion(MediaPlayer mp) { - mp.release(); - } - }); - } catch (Exception ignore) { - } - } - /** * Is used to ensure the UI entered data is within the bounds of the trait's min/max * @@ -528,7 +506,7 @@ public boolean validateData() { removeTrait(trait); collectInputView.clear(); - playSound("error"); + soundHelper.playError(); return false; } @@ -1678,15 +1656,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { //play success or error sound if the plotId was not found if (success) { - playSound("hero_simple_celebration"); + soundHelper.playCelebrate(); } else { boolean found = false; FieldObject studyObj = null; - ObservationUnitModel[] models = ObservationUnitDao.Companion.getAll(); + ObservationUnitModel[] models = database.getAllObservationUnits(); for (ObservationUnitModel m : models) { if (m.getObservation_unit_db_id().equals(inputPlotId)) { - FieldObject study = StudyDao.Companion.getFieldObject(m.getStudy_id()); + FieldObject study = database.getFieldObject(m.getStudy_id()); if (study != null && study.getExp_name() != null) { studyObj = study; found = true; @@ -1703,11 +1681,11 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { String msg = getString(R.string.act_collect_barcode_search_exists_in_other_field, fieldName); SnackbarUtils.showNavigateSnack(getLayoutInflater(), findViewById(R.id.traitHolder), msg, 8000, null, - (v) -> switchField(studyId, fieldName, null)); + (v) -> switchField(studyId, null)); } else { - playSound("alert_error"); + soundHelper.playError(); Utils.makeToast(getApplicationContext(), getString(R.string.main_toolbar_moveto_no_match)); @@ -2060,4 +2038,16 @@ public void onInfoBarClicked(int position) { infoBarHelper.showInfoBarChoiceDialog(position); } + + @NonNull + @Override + public FieldSwitcher getFieldSwitcher() { + return fieldSwitcher; + } + + @NonNull + @Override + public SoundHelperImpl getSoundHelper() { + return soundHelper; + } } \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/activities/ConfigActivity.java b/app/src/main/java/com/fieldbook/tracker/activities/ConfigActivity.java index 79bba30a2..a996ce6f5 100644 --- a/app/src/main/java/com/fieldbook/tracker/activities/ConfigActivity.java +++ b/app/src/main/java/com/fieldbook/tracker/activities/ConfigActivity.java @@ -44,13 +44,16 @@ import com.fieldbook.tracker.brapi.service.BrAPIService; import com.fieldbook.tracker.database.DataHelper; import com.fieldbook.tracker.database.dao.StudyDao; +import com.fieldbook.tracker.database.models.ObservationUnitModel; import com.fieldbook.tracker.objects.FieldObject; import com.fieldbook.tracker.objects.TraitObject; import com.fieldbook.tracker.preferences.GeneralKeys; import com.fieldbook.tracker.utilities.AppLanguageUtil; import com.fieldbook.tracker.utilities.CSVWriter; import com.fieldbook.tracker.utilities.Constants; +import com.fieldbook.tracker.utilities.FieldSwitchImpl; import com.fieldbook.tracker.utilities.OldPhotosMigrator; +import com.fieldbook.tracker.utilities.SoundHelperImpl; import com.fieldbook.tracker.utilities.TapTargetUtil; import com.fieldbook.tracker.utilities.Utils; import com.fieldbook.tracker.utilities.ZipUtil; @@ -111,6 +114,10 @@ public class ConfigActivity extends ThemedActivity { private final Runnable exportData = () -> new ExportDataTask().execute(0); @Inject public DataHelper database; + @Inject + public FieldSwitchImpl fieldSwitcher; + @Inject + public SoundHelperImpl soundHelper; Handler mHandler = new Handler(); boolean doubleBackToExitPressedOnce = false; ListView settingsList; @@ -711,6 +718,107 @@ private void showSaveDialog() { }); } + private void resolveFuzzySearchResult(FieldObject f, @Nullable String plotId) { + + soundHelper.playCelebrate(); + + int studyId = ep.getInt(GeneralKeys.SELECTED_FIELD_ID, 0); + + int newStudyId = f.getExp_id(); + + if (studyId != newStudyId) { + + switchField(newStudyId); + + } + + Intent intent = new Intent(this, CollectActivity.class); + CollectActivity.reloadData = true; + + if (plotId != null) { + + ep.edit().putString(GeneralKeys.LAST_PLOT, plotId).apply(); + + } + + startActivity(intent); + + } + @Nullable + private FieldObject searchStudiesForBarcode(String barcode) { + + // first, search to try and match study alias (brapi stores study_db_id here) + ArrayList fields = database.getAllFieldObjects(); + + // start by searching for alias + for (FieldObject f : fields) { + + if (f != null && f.getExp_alias() != null && f.getExp_alias().equals(barcode)) { + + return f; + + } + } + + // second, if field is not found search for study name + for (FieldObject f : fields) { + + if (f != null && f.getExp_name() != null && f.getExp_name().equals(barcode)) { + + return f; + + } + } + + return null; + } + + @Nullable + private ObservationUnitModel searchPlotsForBarcode(String barcode) { + + // search for barcode in database + ObservationUnitModel[] models = database.getAllObservationUnits(); + for (ObservationUnitModel m : models) { + if (m.getObservation_unit_db_id().equals(barcode)) { + + return m; + } + } + + return null; + } + + //1) study alias, 2) study names, 3) plotdbids + private void fuzzyBarcodeSearch(String barcode) { + + // search for studies + FieldObject f = searchStudiesForBarcode(barcode); + + if (f == null) { + + // search for plots + ObservationUnitModel m = searchPlotsForBarcode(barcode); + + if (m != null && m.getStudy_id() != -1) { + + FieldObject study = database.getFieldObject(m.getStudy_id()); + + resolveFuzzySearchResult(study, barcode); + + } else { + + soundHelper.playError(); + + Utils.makeToast(this, getString(R.string.act_config_fuzzy_search_failed, barcode)); + } + + } else { + + resolveFuzzySearchResult(f, null); + + } + } + @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -718,11 +826,23 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten if (resultCode != Activity.RESULT_OK) finish(); } else if (requestCode == REQUEST_BARCODE) { if (resultCode == RESULT_OK) { - // store barcode value as data + + // get barcode from scan result IntentResult plotDataResult = IntentIntegrator.parseActivityResult(resultCode, data); String scannedBarcode = plotDataResult.getContents(); - startActivity(new Intent(this, CollectActivity.class) - .putExtra("barcode", scannedBarcode)); + + try { + + fuzzyBarcodeSearch(scannedBarcode); + + } catch (Exception e) { + + e.printStackTrace(); + + Utils.makeToast(this, getString(R.string.act_config_fuzzy_search_error, scannedBarcode)); + + soundHelper.playError(); + } } } } @@ -871,22 +991,8 @@ public void selectFirstField() { */ private void switchField(int studyId) { - FieldObject f = StudyDao.Companion.getFieldObject(studyId); - - if (f != null) { + fieldSwitcher.switchField(studyId); - database.switchField(studyId); - - //clear field selection after updates - ep.edit().putInt(GeneralKeys.SELECTED_FIELD_ID, studyId) - .putString(GeneralKeys.FIELD_FILE, f.getExp_name()) - .putString(GeneralKeys.FIELD_OBS_LEVEL, f.getObservation_level()) - .putString(GeneralKeys.UNIQUE_NAME, f.getUnique_id()) - .putString(GeneralKeys.PRIMARY_NAME, f.getPrimary_id()) - .putString(GeneralKeys.SECONDARY_NAME, f.getSecondary_id()) - .putBoolean(GeneralKeys.IMPORT_FIELD_FINISHED, true) - .putString(GeneralKeys.LAST_PLOT, null).apply(); - } } private class ExportDataTask extends AsyncTask { diff --git a/app/src/main/java/com/fieldbook/tracker/activities/FieldEditorActivity.java b/app/src/main/java/com/fieldbook/tracker/activities/FieldEditorActivity.java index b12edd4a5..cf29b54cf 100644 --- a/app/src/main/java/com/fieldbook/tracker/activities/FieldEditorActivity.java +++ b/app/src/main/java/com/fieldbook/tracker/activities/FieldEditorActivity.java @@ -45,11 +45,13 @@ import com.fieldbook.tracker.dialogs.FieldSortDialog; import com.fieldbook.tracker.interfaces.FieldAdapterController; import com.fieldbook.tracker.interfaces.FieldSortController; +import com.fieldbook.tracker.interfaces.FieldSwitcher; import com.fieldbook.tracker.location.GPSTracker; import com.fieldbook.tracker.objects.FieldFileObject; import com.fieldbook.tracker.objects.FieldObject; import com.fieldbook.tracker.preferences.GeneralKeys; import com.fieldbook.tracker.utilities.DocumentTreeUtil; +import com.fieldbook.tracker.utilities.FieldSwitchImpl; import com.fieldbook.tracker.utilities.TapTargetUtil; import com.fieldbook.tracker.utilities.Utils; import com.getkeepsafe.taptargetview.TapTarget; @@ -105,6 +107,9 @@ public class FieldEditorActivity extends ThemedActivity @Inject DataHelper database; + @Inject + FieldSwitchImpl fieldSwitcher; + // Creates a new thread to do importing private final Runnable importRunnable = new Runnable() { public void run() { @@ -120,7 +125,7 @@ public void run() { // Helper function to load data public void loadData(ArrayList fields) { try { - mAdapter = new FieldAdapter(thisActivity, fields); + mAdapter = new FieldAdapter(thisActivity, fields, fieldSwitcher); fieldList.setAdapter(mAdapter); } catch (Exception e) { e.printStackTrace(); @@ -170,7 +175,7 @@ public void onCreate(Bundle savedInstanceState) { thisActivity = this; database.updateExpTable(false, true, false, ep.getInt(GeneralKeys.SELECTED_FIELD_ID, 0)); fieldList = findViewById(R.id.myList); - mAdapter = new FieldAdapter(thisActivity, database.getAllFieldObjects()); + mAdapter = new FieldAdapter(thisActivity, database.getAllFieldObjects(), fieldSwitcher); fieldList.setAdapter(mAdapter); } @@ -356,7 +361,7 @@ public boolean onOptionsItemSelected(MenuItem item) { //update list of fields fieldList = findViewById(R.id.myList); - mAdapter = new FieldAdapter(thisActivity, database.getAllFieldObjects()); + mAdapter = new FieldAdapter(thisActivity, database.getAllFieldObjects(), fieldSwitcher); fieldList.setAdapter(mAdapter); })); @@ -799,7 +804,8 @@ public void submitSortList(FieldObject field, String[] attributes) { database.updateStudySort(joiner.toString(), field.getExp_id()); if (ep.getInt(GeneralKeys.SELECTED_FIELD_ID, 0) == field.getExp_id()) { - database.switchField(field.getExp_id()); + + fieldSwitcher.switchField(field); CollectActivity.reloadData = true; } @@ -838,4 +844,10 @@ public DataHelper getDatabase() { public SharedPreferences getPreferences() { return PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); } + + @NonNull + @Override + public FieldSwitcher getFieldSwitcher() { + return fieldSwitcher; + } } \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/adapters/FieldAdapter.java b/app/src/main/java/com/fieldbook/tracker/adapters/FieldAdapter.java index a0d39224e..45d32d439 100644 --- a/app/src/main/java/com/fieldbook/tracker/adapters/FieldAdapter.java +++ b/app/src/main/java/com/fieldbook/tracker/adapters/FieldAdapter.java @@ -21,8 +21,8 @@ import com.fieldbook.tracker.brapi.BrapiInfoDialog; import com.fieldbook.tracker.dialogs.BrapiSyncObsDialog; import com.fieldbook.tracker.interfaces.FieldAdapterController; -import com.fieldbook.tracker.interfaces.FieldController; import com.fieldbook.tracker.interfaces.FieldSortController; +import com.fieldbook.tracker.interfaces.FieldSwitcher; import com.fieldbook.tracker.objects.FieldObject; import com.fieldbook.tracker.preferences.GeneralKeys; @@ -40,11 +40,12 @@ public class FieldAdapter extends BaseAdapter { private final ArrayList list; private final Context context; private SharedPreferences ep; - - public FieldAdapter(Context context, ArrayList list) { + private final FieldSwitcher fieldSwitcher; + public FieldAdapter(Context context, ArrayList list, FieldSwitcher switcher) { this.context = context; mLayoutInflater = LayoutInflater.from(context); this.list = list; + this.fieldSwitcher = switcher; } public int getCount() { @@ -151,10 +152,20 @@ public void onClick(View v) { //Check both file name and observation level if (ep.getInt(GeneralKeys.SELECTED_FIELD_ID, -1) != -1) { - holder.active.setChecked((ep.getString(GeneralKeys.FIELD_FILE, "") - .contentEquals(holder.fieldName.getText())) && - (ep.getString(GeneralKeys.FIELD_OBS_LEVEL, "") - .contentEquals(holder.observationLevel.getText()))); + FieldObject field = getItem(position); + + if (field.getExp_source() == null) { + holder.active.setChecked((ep.getString(GeneralKeys.FIELD_FILE, "") + .contentEquals(holder.fieldName.getText())) && + (ep.getString(GeneralKeys.FIELD_OBS_LEVEL, "") + .contentEquals(holder.observationLevel.getText()))); + } else if (field.getExp_alias() != null) { + String alias = ep.getString(GeneralKeys.FIELD_ALIAS, ""); + String level = ep.getString(GeneralKeys.FIELD_OBS_LEVEL, ""); + holder.active.setChecked(alias.contentEquals(field.getExp_alias()) + && level.contentEquals(holder.observationLevel.getText())); + } + } else holder.active.setChecked(false); holder.menuPopup.setOnClickListener(makeMenuPopListener(position)); @@ -248,11 +259,7 @@ private void fieldClick(FieldObject selectedField) { setEditorItem(ep, selectedField); - SharedPreferences.Editor ed = ep.edit(); - ed.putInt(GeneralKeys.SELECTED_FIELD_ID, selectedField.getExp_id()); - ed.apply(); - - ((FieldController) context).getDatabase().switchField(selectedField.getExp_id()); + fieldSwitcher.switchField(selectedField); CollectActivity.reloadData = true; notifyDataSetChanged(); diff --git a/app/src/main/java/com/fieldbook/tracker/async/ImportRunnableTask.java b/app/src/main/java/com/fieldbook/tracker/async/ImportRunnableTask.java index bd5a87176..8103a6267 100644 --- a/app/src/main/java/com/fieldbook/tracker/async/ImportRunnableTask.java +++ b/app/src/main/java/com/fieldbook/tracker/async/ImportRunnableTask.java @@ -232,21 +232,13 @@ protected void onPostExecute(Integer result) { } else { SharedPreferences.Editor ed = mPrefs.edit(); - ed.putString(GeneralKeys.UNIQUE_NAME, unique); - ed.putString(GeneralKeys.PRIMARY_NAME, primary); - ed.putString(GeneralKeys.SECONDARY_NAME, secondary); - ed.putBoolean(GeneralKeys.IMPORT_FIELD_FINISHED, true); - ed.putInt(GeneralKeys.SELECTED_FIELD_ID, result); - - ed.apply(); - CollectActivity.reloadData = true; controller.queryAndLoadFields(); try { - controller.getDatabase().switchField(result); + controller.getFieldSwitcher().switchField(result); } catch (Exception e) { diff --git a/app/src/main/java/com/fieldbook/tracker/database/dao/StudyDao.kt b/app/src/main/java/com/fieldbook/tracker/database/dao/StudyDao.kt index 5c5287da3..ac74e49ca 100644 --- a/app/src/main/java/com/fieldbook/tracker/database/dao/StudyDao.kt +++ b/app/src/main/java/com/fieldbook/tracker/database/dao/StudyDao.kt @@ -5,9 +5,17 @@ import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteException import android.util.Log import androidx.core.content.contentValuesOf -import com.fieldbook.tracker.database.* -import com.fieldbook.tracker.database.Migrator.* import com.fieldbook.tracker.database.Migrator.Companion.sObservationUnitPropertyViewName +import com.fieldbook.tracker.database.Migrator.Observation +import com.fieldbook.tracker.database.Migrator.ObservationUnit +import com.fieldbook.tracker.database.Migrator.ObservationUnitAttribute +import com.fieldbook.tracker.database.Migrator.ObservationUnitValue +import com.fieldbook.tracker.database.Migrator.Study +import com.fieldbook.tracker.database.getTime +import com.fieldbook.tracker.database.query +import com.fieldbook.tracker.database.toFirst +import com.fieldbook.tracker.database.toTable +import com.fieldbook.tracker.database.withDatabase import com.fieldbook.tracker.objects.FieldObject @@ -184,9 +192,11 @@ class StudyDao { db.query(Study.tableName, select = arrayOf(Study.PK, "study_name", + "study_alias", "study_unique_id_name", "study_primary_id_name", "study_secondary_id_name", + "observation_levels", "date_import", "date_edit", "date_export", diff --git a/app/src/main/java/com/fieldbook/tracker/interfaces/CollectController.kt b/app/src/main/java/com/fieldbook/tracker/interfaces/CollectController.kt index f554039d6..7d00d786b 100644 --- a/app/src/main/java/com/fieldbook/tracker/interfaces/CollectController.kt +++ b/app/src/main/java/com/fieldbook/tracker/interfaces/CollectController.kt @@ -1,6 +1,7 @@ package com.fieldbook.tracker.interfaces import android.os.HandlerThread +import com.fieldbook.tracker.utilities.SoundHelperImpl import com.fieldbook.tracker.views.CollectInputView import com.fieldbook.tracker.views.RangeBoxView import com.fieldbook.tracker.views.TraitBoxView @@ -10,7 +11,7 @@ interface CollectController: FieldController { fun getRangeBox(): RangeBoxView fun getTraitBox(): TraitBoxView fun getInputView(): CollectInputView - fun playSound(sound: String) + fun getSoundHelper(): SoundHelperImpl fun resetGeoNavMessages() fun getSecurityChecker(): SecureBluetoothActivityImpl fun getAverageHandler(): HandlerThread diff --git a/app/src/main/java/com/fieldbook/tracker/interfaces/FieldController.kt b/app/src/main/java/com/fieldbook/tracker/interfaces/FieldController.kt index d537e3f4d..b2dd8097b 100644 --- a/app/src/main/java/com/fieldbook/tracker/interfaces/FieldController.kt +++ b/app/src/main/java/com/fieldbook/tracker/interfaces/FieldController.kt @@ -6,4 +6,5 @@ import com.fieldbook.tracker.database.DataHelper interface FieldController { fun getDatabase(): DataHelper fun getPreferences(): SharedPreferences + fun getFieldSwitcher(): FieldSwitcher } \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/interfaces/FieldSwitcher.kt b/app/src/main/java/com/fieldbook/tracker/interfaces/FieldSwitcher.kt new file mode 100644 index 000000000..ca4aadc03 --- /dev/null +++ b/app/src/main/java/com/fieldbook/tracker/interfaces/FieldSwitcher.kt @@ -0,0 +1,12 @@ +package com.fieldbook.tracker.interfaces + +import com.fieldbook.tracker.objects.FieldObject + +/** + * Any object with access to a context and database can switch fields if this is implemented. + * Default implementation available in utils FieldSwitchImpl + */ +interface FieldSwitcher { + fun switchField(field: FieldObject?) + fun switchField(studyId: Int) +} \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/objects/GeoNavHelper.kt b/app/src/main/java/com/fieldbook/tracker/objects/GeoNavHelper.kt index a83fbe111..e7b02be0c 100644 --- a/app/src/main/java/com/fieldbook/tracker/objects/GeoNavHelper.kt +++ b/app/src/main/java/com/fieldbook/tracker/objects/GeoNavHelper.kt @@ -7,7 +7,11 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.graphics.Color -import android.hardware.* +import android.hardware.GeomagneticField +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager import android.location.Location import android.os.Handler import android.os.HandlerThread @@ -66,7 +70,7 @@ class GeoNavHelper @Inject constructor(@ActivityContext private val context: Con if (time > mLastGeoNavTime) { if (!mFirstLocationFound) { mFirstLocationFound = true - (context as CollectActivity).playSound("cycle") + (context as CollectActivity).getSoundHelper().playCycle() Utils.makeToast(context, context.getString(R.string.act_collect_geonav_first_location_found) ) @@ -136,9 +140,16 @@ class GeoNavHelper @Inject constructor(@ActivityContext private val context: Con private var mGeoNavLogWriter: OutputStreamWriter? = null init { + init() + } + + private fun init() { mMessageHandlerThread.start() + mMessageHandlerThread.looper mSchedulerHandler.start() + mSchedulerHandler.looper mAverageHandler.start() + mAverageHandler.looper } /** diff --git a/app/src/main/java/com/fieldbook/tracker/preferences/GeneralKeys.java b/app/src/main/java/com/fieldbook/tracker/preferences/GeneralKeys.java index cc2395774..465f6a306 100644 --- a/app/src/main/java/com/fieldbook/tracker/preferences/GeneralKeys.java +++ b/app/src/main/java/com/fieldbook/tracker/preferences/GeneralKeys.java @@ -124,6 +124,9 @@ public class GeneralKeys { //example: field_sample how to get: sharedPreferences.getString(Constants.FIELD_FILE, "") public static final String FIELD_FILE = "FieldFile"; + //field alias is currently used from imported brapi studies, it is the study db id + public static final String FIELD_ALIAS = "FieldAlias"; + //key that saves where the field source is from local, brapi, etc. public static final String FIELD_SOURCE = "ImportExpSource"; diff --git a/app/src/main/java/com/fieldbook/tracker/traits/BaseTraitLayout.java b/app/src/main/java/com/fieldbook/tracker/traits/BaseTraitLayout.java index b2a788d34..5f736e9d9 100644 --- a/app/src/main/java/com/fieldbook/tracker/traits/BaseTraitLayout.java +++ b/app/src/main/java/com/fieldbook/tracker/traits/BaseTraitLayout.java @@ -196,7 +196,7 @@ public void deleteTraitListener() { } //check if sound on delete is enabled in preferences and play sound if (getPrefs().getBoolean(GeneralKeys.DELETE_OBSERVATION_SOUND, false)) { - controller.playSound("delete"); + controller.getSoundHelper().playDelete(); } } diff --git a/app/src/main/java/com/fieldbook/tracker/utilities/FieldSwitchImpl.kt b/app/src/main/java/com/fieldbook/tracker/utilities/FieldSwitchImpl.kt new file mode 100644 index 000000000..141a41c32 --- /dev/null +++ b/app/src/main/java/com/fieldbook/tracker/utilities/FieldSwitchImpl.kt @@ -0,0 +1,48 @@ +package com.fieldbook.tracker.utilities + +import android.content.Context +import com.fieldbook.tracker.database.DataHelper +import com.fieldbook.tracker.interfaces.FieldSwitcher +import com.fieldbook.tracker.objects.FieldObject +import com.fieldbook.tracker.preferences.GeneralKeys +import dagger.hilt.android.qualifiers.ActivityContext +import javax.inject.Inject + +/** + * Field Switcher implementation allows an object with context to switch currently selected field. + * This handles all necessary preferences and database updates. + */ +class FieldSwitchImpl @Inject constructor(@ActivityContext private val context: Context): FieldSwitcher { + + @Inject + lateinit var database: DataHelper + + private val prefs by lazy { + context.getSharedPreferences(GeneralKeys.SHARED_PREF_FILE_NAME, Context.MODE_PRIVATE) + } + + override fun switchField(studyId: Int) { + val f = database.getFieldObject(studyId) + switchField(f) + } + + override fun switchField(field: FieldObject?) { + + if (field != null && field.exp_id != -1) { + + database.switchField(field.exp_id) + + //clear field selection after updates + prefs.edit().putInt(GeneralKeys.SELECTED_FIELD_ID, field.exp_id) + .putString(GeneralKeys.FIELD_FILE, field.exp_name) + .putString(GeneralKeys.FIELD_ALIAS, field.exp_alias) + .putString(GeneralKeys.FIELD_OBS_LEVEL, field.observation_level) + .putString(GeneralKeys.UNIQUE_NAME, field.unique_id) + .putString(GeneralKeys.PRIMARY_NAME, field.primary_id) + .putString(GeneralKeys.SECONDARY_NAME, field.secondary_id) + .putBoolean(GeneralKeys.IMPORT_FIELD_FINISHED, true) + .putString(GeneralKeys.LAST_PLOT, null).apply() + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/utilities/SoundHelperImpl.kt b/app/src/main/java/com/fieldbook/tracker/utilities/SoundHelperImpl.kt new file mode 100644 index 000000000..039370282 --- /dev/null +++ b/app/src/main/java/com/fieldbook/tracker/utilities/SoundHelperImpl.kt @@ -0,0 +1,59 @@ +package com.fieldbook.tracker.utilities + +import android.content.Context +import android.media.MediaPlayer +import dagger.hilt.android.qualifiers.ActivityContext +import javax.inject.Inject + +/** + * Plays a sound from the raw resources folder. + */ +class SoundHelperImpl @Inject constructor(@ActivityContext private val context: Context) { + + companion object { + const val PLONK = "plonk" + const val ADVANCE = "advance" + const val CYCLE = "cycle" + const val ERROR = "error" + const val CELEBRATE = "hero_simple_celebration" + const val ALERT_ERROR = "alert_error" + const val DELETE = "delete" + } + + fun playPlonk() { + playSound(PLONK) + } + + fun playAdvance() { + playSound(ADVANCE) + } + + fun playCycle() { + playSound(CYCLE) + } + + fun playError() { + playSound(ERROR) + } + + fun playCelebrate() { + playSound(CELEBRATE) + } + + fun playAlertError() { + playSound(ALERT_ERROR) + } + + fun playDelete() { + playSound(DELETE) + } + + fun playSound(sound: String?) { + try { + val resID: Int = context.resources.getIdentifier(sound, "raw", context.packageName) + val chimePlayer = MediaPlayer.create(context, resID) + chimePlayer.start() + chimePlayer.setOnCompletionListener { mp -> mp.release() } + } catch (ignore: Exception) { } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/views/RangeBoxView.kt b/app/src/main/java/com/fieldbook/tracker/views/RangeBoxView.kt index 84ffc41e5..54c4b98c0 100644 --- a/app/src/main/java/com/fieldbook/tracker/views/RangeBoxView.kt +++ b/app/src/main/java/com/fieldbook/tracker/views/RangeBoxView.kt @@ -384,7 +384,7 @@ class RangeBoxView : ConstraintLayout { if (controller.getPreferences().getBoolean(GeneralKeys.PRIMARY_SOUND, false)) { if (cRange.range != lastRange && lastRange != "") { lastRange = cRange.range - controller.playSound("plonk") + controller.getSoundHelper().playPlonk() } } display() @@ -441,7 +441,7 @@ class RangeBoxView : ConstraintLayout { if (controller.getPreferences().getBoolean(GeneralKeys.PRIMARY_SOUND, false)) { if (cRange.range != lastRange && lastRange != "") { lastRange = cRange.range - controller.playSound("plonk") + controller.getSoundHelper().playPlonk() } } } @@ -534,12 +534,12 @@ class RangeBoxView : ConstraintLayout { } if (controller.getPreferences().getBoolean(GeneralKeys.ENTRY_NAVIGATION_SOUND, false) ) { - controller.playSound("advance") + controller.getSoundHelper().playAdvance() } val entryArrow = controller.getPreferences().getString(GeneralKeys.DISABLE_ENTRY_ARROW_NO_DATA, "0") if ((entryArrow == "1" || entryArrow == "3") && !controller.getTraitBox().existsTrait()) { - controller.playSound("error") + controller.getSoundHelper().playError() } else { if (rangeID.isNotEmpty()) { //index.setEnabled(true); @@ -557,12 +557,12 @@ class RangeBoxView : ConstraintLayout { } if (controller.getPreferences().getBoolean(GeneralKeys.ENTRY_NAVIGATION_SOUND, false) ) { - controller.playSound("advance") + controller.getSoundHelper().playAdvance() } val entryArrow = controller.getPreferences().getString(GeneralKeys.DISABLE_ENTRY_ARROW_NO_DATA, "0") if ((entryArrow == "2" || entryArrow == "3") && !controller.getTraitBox().existsTrait()) { - controller.playSound("error") + controller.getSoundHelper().playError() } else { if (rangeID.isNotEmpty()) { //index.setEnabled(true); diff --git a/app/src/main/java/com/fieldbook/tracker/views/TraitBoxView.kt b/app/src/main/java/com/fieldbook/tracker/views/TraitBoxView.kt index c0f25f96a..0f658bf21 100644 --- a/app/src/main/java/com/fieldbook/tracker/views/TraitBoxView.kt +++ b/app/src/main/java/com/fieldbook/tracker/views/TraitBoxView.kt @@ -7,7 +7,11 @@ import android.view.MotionEvent import android.view.View import android.view.View.OnTouchListener import android.view.inputmethod.InputMethodManager -import android.widget.* +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.ImageView +import android.widget.Spinner +import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import com.fieldbook.tracker.R import com.fieldbook.tracker.interfaces.CollectTraitController @@ -322,7 +326,7 @@ class TraitBoxView : ConstraintLayout { rangeBox.clickLeft() } if (controller.getPreferences().getBoolean(GeneralKeys.CYCLE_TRAITS_SOUND, false)) { - controller.playSound("cycle") + controller.getSoundHelper().playCycle() } } } else if (direction == "right") { @@ -333,7 +337,7 @@ class TraitBoxView : ConstraintLayout { rangeBox.clickRight() } if (controller.getPreferences().getBoolean(GeneralKeys.CYCLE_TRAITS_SOUND, false)) { - controller.playSound("cycle") + controller.getSoundHelper().playCycle() } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b2458c327..729d36dc3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -802,4 +802,6 @@ Field Book is up to date. Search all plots and fields to load/navigate to the barcoded item. Barcode not found.\n + Database could not retrieve a field or plot with code: %s + Something went wrong when searching for %s