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 7abb91e83..e3f871533 100644 --- a/app/src/main/java/com/fieldbook/tracker/activities/CollectActivity.java +++ b/app/src/main/java/com/fieldbook/tracker/activities/CollectActivity.java @@ -29,7 +29,6 @@ import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.ListView; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -409,7 +408,7 @@ private void checkForInitialBarcodeSearch() { } else { - Toast.makeText(this, getString(R.string.act_collect_plot_with_code_not_found), Toast.LENGTH_LONG).show(); + Utils.makeToast(getApplicationContext(), getString(R.string.act_collect_plot_with_code_not_found)); } } @@ -836,7 +835,7 @@ public boolean moveToSearch( } if (!command.equals("quickgoto") && !command.equals("barcode")) - Utils.makeToast(getApplicationContext(), getString(R.string.main_toolbar_moveto_no_match)); + Utils.makeToast(this, getString(R.string.main_toolbar_moveto_no_match)); return false; } @@ -1185,7 +1184,7 @@ public String getLocationByPreferences() { } private void brapiDelete(String parent, Boolean hint) { - Toast.makeText(getApplicationContext(), getString(R.string.brapi_delete_message), Toast.LENGTH_LONG).show(); + Utils.makeToast(this, getString(R.string.brapi_delete_message)); TraitObject trait = traitBox.getCurrentTrait(); updateObservation(trait, getString(R.string.brapi_na), null); if (hint) { @@ -1291,7 +1290,7 @@ private void openSavedResourceFile() { e.printStackTrace(); } } else { - Toast.makeText(this, "No file preference saved, select a file with a short press", Toast.LENGTH_SHORT).show(); + Utils.makeToast(this, "No file preference saved, select a file with a short press"); } } @@ -1402,9 +1401,18 @@ public boolean onOptionsItemSelected(MenuItem item) { i.putExtra("trait", traitBox.getCurrentTrait().getRealPosition()); startActivityForResult(i, 2); } else if (itemId == lockDataId) { - if (dataLocked == UNLOCKED) dataLocked = LOCKED; - else if (dataLocked == LOCKED) dataLocked = FROZEN; - else dataLocked = UNLOCKED; + if (dataLocked == UNLOCKED) { + dataLocked = LOCKED; + Utils.makeToast(this, getString(R.string.activity_collect_locked_state)); + } + else if (dataLocked == LOCKED) { + dataLocked = FROZEN; + Utils.makeToast(this, getString(R.string.activity_collect_frozen_state)); + } + else { + dataLocked = UNLOCKED; + Utils.makeToast(this, getString(R.string.activity_collect_unlocked_state)); + } preferences.edit().putInt(GeneralKeys.DATA_LOCK_STATE, dataLocked).apply(); lockData(); } else if (itemId == android.R.id.home) { @@ -1449,35 +1457,23 @@ public boolean onOptionsItemSelected(MenuItem item) { // if trait audio is recording, give a warning if (isTraitAudioRecording) { - Toast.makeText( - this, R.string.trait_audio_recording_warning, - Toast.LENGTH_SHORT - ).show(); + Utils.makeToast(this, getString(R.string.trait_audio_recording_warning)); } // if trait audio is playing, give a warning else if (isTraitAudioPlaying) { - Toast.makeText( - this, R.string.trait_audio_playing_warning, - Toast.LENGTH_SHORT - ).show(); + Utils.makeToast(this, getString(R.string.trait_audio_playing_warning)); } // if trait audio isn't recording or playing // record or stop the field audio depending on its state else if (!fieldAudioHelper.isRecording()) { // TODO: add trait audio playback stopping logic fieldAudioHelper.startRecording(true); - Toast.makeText( - this, R.string.field_audio_recording_start, - Toast.LENGTH_SHORT - ).show(); + Utils.makeToast(this, getString(R.string.field_audio_recording_start)); micItem.setIcon(R.drawable.ic_tb_field_mic_on); micItem.setTitle(R.string.menu_collect_stop_field_audio); } else { fieldAudioHelper.stopRecording(); - Toast.makeText( - this, R.string.field_audio_recording_stop, - Toast.LENGTH_SHORT - ).show(); + Utils.makeToast(this, getString(R.string.field_audio_recording_stop)); micItem.setIcon(R.drawable.ic_tb_field_mic_off); micItem.setTitle(R.string.menu_collect_start_field_audio); } @@ -1579,7 +1575,7 @@ private void showMultiMeasureDeleteDialog() { } } else { - Toast.makeText(this, R.string.dialog_multi_measure_delete_no_observations, Toast.LENGTH_SHORT).show(); + Utils.makeToast(this, getString(R.string.dialog_multi_measure_delete_no_observations)); } } @@ -1650,7 +1646,7 @@ void lockData() { if (state == LOCKED) { systemMenu.findItem(R.id.lockData).setIcon(R.drawable.ic_tb_lock); - disableDataEntry(); + disableDataEntry(R.string.activity_collect_locked_state); } else if (state == UNLOCKED) { systemMenu.findItem(R.id.lockData).setIcon(R.drawable.ic_tb_unlock); enableDataEntry(); @@ -1658,7 +1654,7 @@ void lockData() { systemMenu.findItem(R.id.lockData).setIcon(R.drawable.ic_lock_clock); if (collectInputView.getText().isEmpty()) { enableDataEntry(); - } else disableDataEntry(); + } else disableDataEntry(R.string.activity_collect_frozen_state); } TraitObject trait = getCurrentTrait(); @@ -1670,7 +1666,7 @@ void lockData() { public void traitLockData() { if (dataLocked == LOCKED) { systemMenu.findItem(R.id.lockData).setIcon(R.drawable.ic_tb_lock); - disableDataEntry(); + disableDataEntry(R.string.activity_collect_locked_state); } else if (dataLocked == UNLOCKED) { systemMenu.findItem(R.id.lockData).setIcon(R.drawable.ic_tb_unlock); enableDataEntry(); @@ -1678,22 +1674,29 @@ public void traitLockData() { systemMenu.findItem(R.id.lockData).setIcon(R.drawable.ic_lock_clock); if (collectInputView.getText().isEmpty()) { enableDataEntry(); - } else disableDataEntry(); + } else disableDataEntry(R.string.activity_collect_frozen_state); } } private void enableDataEntry() { - missingValue.setEnabled(true); - deleteValue.setEnabled(true); - barcodeInput.setEnabled(true); - traitLayouts.enableViews(); - } - - private void disableDataEntry() { - missingValue.setEnabled(false); - deleteValue.setEnabled(false); - barcodeInput.setEnabled(false); - traitLayouts.disableViews(); +// missingValue.setEnabled(true); +// deleteValue.setEnabled(true); +// barcodeInput.setEnabled(true); +// traitLayouts.enableViews(); + findViewById(R.id.lockOverlay).setVisibility(View.GONE); + } + + private void disableDataEntry(int toastMessageId) { +// missingValue.setEnabled(false); +// deleteValue.setEnabled(false); +// barcodeInput.setEnabled(false); +// traitLayouts.disableViews(); + View overlay = findViewById(R.id.lockOverlay); + overlay.setOnClickListener((v) -> { + getSoundHelper().playError(); + Utils.makeToast(this, getString(toastMessageId)); + }); + overlay.setVisibility(View.VISIBLE); } private void moveToPlotID() { @@ -1847,7 +1850,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } } else { - Toast.makeText(this, R.string.act_file_explorer_no_file_error, Toast.LENGTH_SHORT).show(); + Utils.makeToast(this, getString(R.string.act_file_explorer_no_file_error)); } break; case 2: diff --git a/app/src/main/java/com/fieldbook/tracker/preferences/LanguagePreferenceFragment.kt b/app/src/main/java/com/fieldbook/tracker/preferences/LanguagePreferenceFragment.kt index 852aa2871..d7f802c61 100644 --- a/app/src/main/java/com/fieldbook/tracker/preferences/LanguagePreferenceFragment.kt +++ b/app/src/main/java/com/fieldbook/tracker/preferences/LanguagePreferenceFragment.kt @@ -1,7 +1,9 @@ package com.fieldbook.tracker.preferences +import android.app.AlertDialog import android.content.res.Resources import android.os.Bundle +import android.util.Log import androidx.core.os.ConfigurationCompat import androidx.fragment.app.FragmentManager import androidx.preference.Preference @@ -33,36 +35,35 @@ class LanguagePreferenceFragment : PreferenceFragmentCompat(), Preference.OnPref * Also update the app language using app compat. */ override fun onPreferenceClick(preference: Preference): Boolean { - try { - context?.let { ctx -> - var id = preference.key - + if (preference.key == "com.fieldbook.tracker.preference.language.default") { + id = ConfigurationCompat.getLocales(Resources.getSystem().configuration)[0]?.language ?: "en-US" + } + Log.d("LanguagePrefFragment", "Switching language to: $id") with (PreferenceManager.getDefaultSharedPreferences(ctx)) { - - if (preference.key == "com.fieldbook.tracker.preference.language.default") { - - id = ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)?.language - - } - edit().putString(GeneralKeys.LANGUAGE_LOCALE_ID, id).apply() edit().putString(GeneralKeys.LANGUAGE_LOCALE_SUMMARY, preference.title.toString()).apply() + } - AppLanguageUtil.refreshAppText(context) + AlertDialog.Builder(ctx, R.style.AppAlertDialog).apply { + setTitle(context.getString(R.string.dialog_warning)) + setMessage(context.getString(R.string.preference_language_warning)) + setPositiveButton(context.getString(android.R.string.ok)) { dialog, _ -> + AppLanguageUtil.refreshAppText(ctx) + dialog.dismiss() + parentFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) + } + setCancelable(false) + show() } } - } catch (e: Exception) { - e.printStackTrace() - + Log.e("LanguagePreference", "Error in onPreferenceClick: ${e.message}") } - parentFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) - return true } } \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/traits/CategoricalTraitLayout.java b/app/src/main/java/com/fieldbook/tracker/traits/CategoricalTraitLayout.java index 82d680cfd..3008ee7d2 100644 --- a/app/src/main/java/com/fieldbook/tracker/traits/CategoricalTraitLayout.java +++ b/app/src/main/java/com/fieldbook/tracker/traits/CategoricalTraitLayout.java @@ -184,59 +184,56 @@ private void setAdapter(ArrayList cats) { layoutManager.setAlignItems(AlignItems.STRETCH); gridMultiCat.setLayoutManager(layoutManager); - if (!((CollectActivity) getContext()).isDataLocked()) { + gridMultiCat.setAdapter(new CategoryTraitAdapter(getContext()) { - gridMultiCat.setAdapter(new CategoryTraitAdapter(getContext()) { - - @Override - public void onBindViewHolder(CategoryTraitViewHolder holder, int position) { - holder.bindTo(); + @Override + public void onBindViewHolder(CategoryTraitViewHolder holder, int position) { + holder.bindTo(); - //get the label for this position - BrAPIScaleValidValuesCategories pair = cats.get(position); + //get the label for this position + BrAPIScaleValidValuesCategories pair = cats.get(position); - //update button with the preference based text - if (labelValPref.equals("value")) { + //update button with the preference based text + if (labelValPref.equals("value")) { - holder.mButton.setText(pair.getValue()); + holder.mButton.setText(pair.getValue()); - } else { + } else { - holder.mButton.setText(pair.getLabel()); + holder.mButton.setText(pair.getLabel()); - } + } - //set the buttons tag to the json, when clicked this is updated in db - holder.mButton.setTag(pair); - holder.mButton.setOnClickListener(createClickListener(holder.mButton, position)); + //set the buttons tag to the json, when clicked this is updated in db + holder.mButton.setTag(pair); + holder.mButton.setOnClickListener(createClickListener(holder.mButton, position)); - //update the button's state if this category is selected - String currentText = getCollectInputView().getText(); + //update the button's state if this category is selected + String currentText = getCollectInputView().getText(); - if (labelValPref.equals("value")) { + if (labelValPref.equals("value")) { - if (currentText.equals(pair.getValue())) { + if (currentText.equals(pair.getValue())) { - pressOnButton(holder.mButton); + pressOnButton(holder.mButton); - } else pressOffButton(holder.mButton); + } else pressOffButton(holder.mButton); - } else { + } else { - if (currentText.equals(pair.getLabel())) { + if (currentText.equals(pair.getLabel())) { - pressOnButton(holder.mButton); + pressOnButton(holder.mButton); - } else pressOffButton(holder.mButton); - } + } else pressOffButton(holder.mButton); } + } - @Override - public int getItemCount() { - return cats.size(); - } - }); - } + @Override + public int getItemCount() { + return cats.size(); + } + }); gridMultiCat.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override diff --git a/app/src/main/java/com/fieldbook/tracker/traits/LayoutCollections.java b/app/src/main/java/com/fieldbook/tracker/traits/LayoutCollections.java index 3a4720873..207ee1496 100644 --- a/app/src/main/java/com/fieldbook/tracker/traits/LayoutCollections.java +++ b/app/src/main/java/com/fieldbook/tracker/traits/LayoutCollections.java @@ -58,31 +58,33 @@ public void setNaTraitsText(String format) { getTraitLayout(format).setNaTraitsText(); } - public void enableViews() { - for (LinearLayout traitLayout : traitLayouts) { - enableViews(true, traitLayout); - } - } - - public void disableViews() { - for (BaseTraitLayout traitLayout : traitLayouts) { - String type = traitLayout.type(); - if (!type.equals("photo") && !type.equals("audio") && !type.equals("percent")) - enableViews(false, traitLayout); - } - } - - public void enableViews(Boolean toggle, ViewGroup layout) { - layout.setEnabled(false); - for (int i = 0; i < layout.getChildCount(); i++) { - View child = layout.getChildAt(i); - if (child instanceof ViewGroup) { - enableViews(toggle, (ViewGroup) child); - } else { - child.setEnabled(toggle); - } - } - } +// Deprecated - simpler to disable/enable data collection using lockOverlay instead +// +// public void enableViews() { +// for (LinearLayout traitLayout : traitLayouts) { +// enableViews(true, traitLayout); +// } +// } +// +// public void disableViews() { +// for (BaseTraitLayout traitLayout : traitLayouts) { +// String type = traitLayout.type(); +// if (!type.equals("photo") && !type.equals("audio") && !type.equals("percent")) +// enableViews(false, traitLayout); +// } +// } +// +// public void enableViews(Boolean toggle, ViewGroup layout) { +// layout.setEnabled(false); +// for (int i = 0; i < layout.getChildCount(); i++) { +// View child = layout.getChildAt(i); +// if (child instanceof ViewGroup) { +// enableViews(toggle, (ViewGroup) child); +// } else { +// child.setEnabled(toggle); +// } +// } +// } public void registerAllReceivers() { for (BaseTraitLayout layout : this.traitLayouts) { diff --git a/app/src/main/java/com/fieldbook/tracker/traits/MultiCatTraitLayout.java b/app/src/main/java/com/fieldbook/tracker/traits/MultiCatTraitLayout.java index 8618ffcc9..ecc345e2c 100644 --- a/app/src/main/java/com/fieldbook/tracker/traits/MultiCatTraitLayout.java +++ b/app/src/main/java/com/fieldbook/tracker/traits/MultiCatTraitLayout.java @@ -112,11 +112,7 @@ public void afterLoadExists(CollectActivity act, @Nullable String value) { if (value != null && value.equals("NA")) controller.getInputView().setText("NA"); - if (!((CollectActivity) getContext()).isDataLocked()) { - - setAdapter(); - - } + setAdapter(); refreshLock(); } diff --git a/app/src/main/java/com/fieldbook/tracker/traits/TextTraitLayout.kt b/app/src/main/java/com/fieldbook/tracker/traits/TextTraitLayout.kt index e3679902c..8fb6cd11a 100644 --- a/app/src/main/java/com/fieldbook/tracker/traits/TextTraitLayout.kt +++ b/app/src/main/java/com/fieldbook/tracker/traits/TextTraitLayout.kt @@ -7,6 +7,7 @@ import android.text.Editable import android.text.TextWatcher import android.util.AttributeSet import android.view.KeyEvent +import android.view.inputmethod.EditorInfo import android.widget.EditText import com.fieldbook.tracker.R import com.fieldbook.tracker.activities.CollectActivity @@ -158,6 +159,8 @@ class TextTraitLayout : BaseTraitLayout { inputEditText?.removeTextChangedListener(textWatcher) super.loadLayout() inputEditText?.isEnabled = !isLocked + inputEditText?.inputType = if (isLocked) EditorInfo.TYPE_NULL else EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS + if (!isLocked) inputEditText?.requestFocus() } override fun afterLoadExists(act: CollectActivity, value: String?) { @@ -228,4 +231,9 @@ class TextTraitLayout : BaseTraitLayout { input.requestFocus() } } + + override fun refreshLock() { + super.refreshLock() + loadLayout() + } } \ No newline at end of file diff --git a/app/src/main/java/com/fieldbook/tracker/utilities/Utils.java b/app/src/main/java/com/fieldbook/tracker/utilities/Utils.java index d7af6715f..b735e38a7 100644 --- a/app/src/main/java/com/fieldbook/tracker/utilities/Utils.java +++ b/app/src/main/java/com/fieldbook/tracker/utilities/Utils.java @@ -12,6 +12,8 @@ public class Utils extends Application { + private static Toast currentToast; + public static void scanFile(Context context, String path, String mimeType) { MediaScannerConnection.scanFile(context, new String[] { path }, new String[] { mimeType }, null); } @@ -59,10 +61,12 @@ public static boolean isConnected(Context context) { NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected(); } - public static void makeToast(Context context, String message) { - Toast toast = Toast.makeText(context, message, Toast.LENGTH_LONG); - toast.setGravity(Gravity.TOP,0,0); - toast.show(); + if (currentToast != null) { + currentToast.cancel(); + } + currentToast = Toast.makeText(context, message, Toast.LENGTH_LONG); + currentToast.setGravity(Gravity.TOP, 0, 0); + currentToast.show(); } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_collect.xml b/app/src/main/res/layout/activity_collect.xml index ebf859fa5..454e6b88f 100644 --- a/app/src/main/res/layout/activity_collect.xml +++ b/app/src/main/res/layout/activity_collect.xml @@ -143,4 +143,16 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 704d47e74..b17476194 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -347,6 +347,11 @@ Choose Observation Update Row Headers + + Locked - data entry, modification and deletion are disabled + Frozen - once data is saved it cannot be modified or deleted + Unlocked - no restrictions on data entry, modification, or deletion + Your device does not have a camera that can be used to take a photo. Are you sure you want to delete this photo? @@ -644,6 +649,7 @@ Language Language set by system System Language + Translations are crowd-sourced and may not be entirely accurate or complete English አማርኛ اَلْعَرَبِيَّةُ