diff --git a/app/build.gradle b/app/build.gradle index 4a5447f..e05eecd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 16 targetSdkVersion 34 versionCode 2 - versionName "1.1" + versionName "2" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' multiDexEnabled = true vectorDrawables.useSupportLibrary = true @@ -40,6 +40,9 @@ android { targetCompatibility 1.8 sourceCompatibility 1.8 } + buildFeatures { + viewBinding true + } } dependencies { @@ -49,16 +52,25 @@ dependencies { }) implementation 'com.journeyapps:zxing-android-embedded:3.6.0' implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.10.0' + implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.vectordrawable:vectordrawable:1.1.0' implementation 'com.github.apl-devs:appintro:v4.2.0' + implementation "androidx.navigation:navigation-fragment-ktx:2.7.7" + implementation 'androidx.preference:preference-ktx:1.1.1' + implementation "androidx.navigation:navigation-ui-ktx:2.7.7" testImplementation 'junit:junit:4.13.2' implementation files('libs/poi-3.12-android-a.jar') + implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") implementation files('libs/poi-ooxml-schemas-3.12-20150511-a.jar') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.google.android.material:material:1.11.0' + implementation 'com.github.daniel-stoneuk:material-about-library:3.1.2' + implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.1" + implementation 'com.google.android.material:material:1.4.0' } repositories { mavenCentral() + maven { url 'https://jitpack.io' } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b290ec8..736a61a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,31 +12,43 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + android:name=".AboutActivity" + android:theme="@style/AppTheme.MaterialAboutActivity" + android:exported="true" /> + + - - - - + android:name=".CompareActivity" + android:configChanges="keyboardHidden|screenSize|keyboard|orientation" + android:windowSoftInputMode="adjustNothing" + android:exported="true" - - - + /> + + + + - \ No newline at end of file + diff --git a/app/src/main/java/org/phenoapps/verify/AboutActivity.java b/app/src/main/java/org/phenoapps/verify/AboutActivity.java new file mode 100644 index 0000000..6f05bba --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/AboutActivity.java @@ -0,0 +1,83 @@ +package org.phenoapps.verify; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.swiperefreshlayout.widget.CircularProgressDrawable; + +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; + +import com.danielstone.materialaboutlibrary.ConvenienceBuilder; +import com.danielstone.materialaboutlibrary.MaterialAboutActivity; +import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; +import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; +import com.danielstone.materialaboutlibrary.model.MaterialAboutList; + +public class AboutActivity extends MaterialAboutActivity { + + + private CircularProgressDrawable progress; + private MaterialAboutActionItem updateCheckItem; + + + + + @NonNull + @Override + protected MaterialAboutList getMaterialAboutList(@NonNull Context context) { + + MaterialAboutCard.Builder appCardBuilder = new MaterialAboutCard.Builder(); + + appCardBuilder.addItem(new MaterialAboutTitleItem.Builder().text("CheckList").icon(R.mipmap.ic_launcher).build()); + + appCardBuilder.addItem(ConvenienceBuilder.createVersionActionItem(this, + getResources().getDrawable(R.drawable.ic_about), + "Version", + false)); + + MaterialAboutCard.Builder authorCardBuilder = new MaterialAboutCard.Builder(); + authorCardBuilder.title("Developers"); + + authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() + .text(getString(R.string.dev_chaney)) + .subText("\t\t"+getString(R.string.ksu)) + .icon(R.drawable.ic_person_profile) + .build()); + authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() + .text(getString(R.string.dev_trevor)) + .subText("\t\t"+getString(R.string.ksu)+"\n\t\t"+getString(R.string.dev_trevor_email)) + .icon(R.drawable.ic_person_profile) + .build()); + authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() + .text(getString(R.string.dev_jesse)) + .subText("\t\t"+getString(R.string.ksu)+"\n\t\t"+getString(R.string.dev_jesse_email)+ + "\n\t\t"+"http://wheatgenetics.org") + .icon(R.drawable.ic_person_profile) + .build()); + + MaterialAboutCard.Builder descriptionCard = new MaterialAboutCard.Builder(); + descriptionCard.title("Description"); + descriptionCard.addItem(new MaterialAboutActionItem.Builder() + .text("Verify is an Android application that imports a list of entries, scans barcodes, and " + + "identifies whether it exists in the list of entries along with audio/visual notifications.").build()); + + return new MaterialAboutList(appCardBuilder.build(),authorCardBuilder.build(), descriptionCard.build()); + } + + @Nullable + @Override + protected CharSequence getActivityTitle() { + return "About"; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progress = new CircularProgressDrawable(this); + progress.setStyle(CircularProgressDrawable.DEFAULT); + progress.start(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/phenoapps/verify/CompareActivity.kt b/app/src/main/java/org/phenoapps/verify/CompareActivity.kt deleted file mode 100644 index 1a066d8..0000000 --- a/app/src/main/java/org/phenoapps/verify/CompareActivity.kt +++ /dev/null @@ -1,199 +0,0 @@ -package org.phenoapps.verify - -import android.app.Activity -import android.os.Bundle -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import android.text.Editable -import android.text.TextWatcher -import android.util.LayoutDirection -import android.view.* -import android.widget.* - -import com.google.zxing.ResultPoint - -import com.journeyapps.barcodescanner.BarcodeCallback -import com.journeyapps.barcodescanner.BarcodeResult -import com.journeyapps.barcodescanner.DecoratedBarcodeView - -class CompareActivity : AppCompatActivity() { - - enum class Mode { - Contains, - Matches - } - - private lateinit var barcodeScannerView: DecoratedBarcodeView - private lateinit var firstEditText: EditText - private lateinit var secondEditText: EditText - private lateinit var imageView: ImageView - - private var mMode: Mode = Mode.Matches - - //keeps track of which edit text is being scanned into, at first it is the top edit text. - private var mFocused: Int = R.id.editText - - private val callback = object : BarcodeCallback { - - override fun barcodeResult(result: BarcodeResult) { - - barcodeScannerView.pause() - - result.text?.let { - - findViewById(mFocused).setText(result.text ?: "") - - mFocused = when(mFocused) { - R.id.editText -> R.id.editText2 - else -> R.id.editText - } - - findViewById(mFocused).requestFocus() - } - - barcodeScannerView.resume() - - } - - override fun possibleResultPoints(resultPoints: List) { - - } - } - - override fun onStart() { - super.onStart() - - val view = layoutInflater.inflate(R.layout.choice_compare_layout, null) - - val radioGroup = view.findViewById(R.id.compare_radio_group) - - val containsRadioButton = radioGroup.findViewById(R.id.radioButton) - val matchesRadioButton = radioGroup.findViewById(R.id.radioButton2) - - containsRadioButton.isChecked = true - - val builder = AlertDialog.Builder(this).apply { - - setView(view) - - setTitle("Choose compare mode:") - - setPositiveButton("OK") { _, _ -> - when (radioGroup.checkedRadioButtonId) { - containsRadioButton.id -> mMode = Mode.Contains - matchesRadioButton.id -> mMode = Mode.Matches - } - } - } - - builder.show() - - imageView = findViewById(R.id.imageView) - firstEditText = findViewById(R.id.editText) - secondEditText = findViewById(R.id.editText2) - - firstEditText.setOnClickListener { - mFocused = R.id.editText - } - - secondEditText.setOnClickListener { - mFocused = R.id.editText2 - } - - val watcher: TextWatcher = object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - } - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - } - - override fun afterTextChanged(s: Editable?) { - - if (firstEditText.text.isNotEmpty() && secondEditText.text.isNotEmpty()) { - - val first = firstEditText.text - val second = secondEditText.text - when (mMode) { - Mode.Contains -> { - when { - first.contains(second) || second.contains(first) -> { - imageView.setImageResource(R.drawable.ic_checkbox_marked_circle) - } - else -> imageView.setImageResource(R.drawable.ic_alpha_x_circle) - } - } - Mode.Matches -> { - when { - firstEditText.text.toString() == secondEditText.text.toString() -> { - imageView.setImageResource(R.drawable.ic_checkbox_marked_circle) - } else -> imageView.setImageResource(R.drawable.ic_alpha_x_circle) - } - } - } - imageView.visibility = View.VISIBLE - } - } - - } - - firstEditText.addTextChangedListener(watcher) - secondEditText.addTextChangedListener(watcher) - - barcodeScannerView = findViewById(org.phenoapps.verify.R.id.zxing_barcode_scanner) - barcodeScannerView.barcodeView.cameraSettings.isContinuousFocusEnabled = true - barcodeScannerView.barcodeView.cameraSettings.isBarcodeSceneModeEnabled = true - barcodeScannerView.decodeContinuous(callback) - - if (supportActionBar != null) { - supportActionBar?.title = "Compare Barcodes" - supportActionBar?.themedContext - supportActionBar?.setDisplayHomeAsUpEnabled(true) - supportActionBar?.setHomeButtonEnabled(true) - } - - imageView.setOnClickListener { - firstEditText.setText("") - secondEditText.setText("") - firstEditText.requestFocus() - imageView.visibility = View.INVISIBLE - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - - super.onCreate(savedInstanceState) - - setContentView(org.phenoapps.verify.R.layout.activity_compare) - - } - - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - - when (item.itemId) { - android.R.id.home -> { - setResult(Activity.RESULT_OK) - finish() - return true - } - else -> return super.onOptionsItemSelected(item) - } - } - - override fun onResume() { - super.onResume() - - barcodeScannerView.resume() - } - - override fun onPause() { - super.onPause() - - barcodeScannerView.pause() - } - - override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { - - return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/phenoapps/verify/CompareFragment.kt b/app/src/main/java/org/phenoapps/verify/CompareFragment.kt new file mode 100644 index 0000000..c6d7d3e --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/CompareFragment.kt @@ -0,0 +1,185 @@ +package org.phenoapps.verify + +import android.content.Context +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.ImageView +import android.widget.RadioGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.google.zxing.ResultPoint +import com.journeyapps.barcodescanner.BarcodeCallback +import com.journeyapps.barcodescanner.BarcodeResult +import com.journeyapps.barcodescanner.DecoratedBarcodeView +import org.phenoapps.verify.ViewModel.CompareViewModel +import com.google.android.material.textfield.TextInputEditText +class CompareFragment : Fragment() { + + private lateinit var view: View + private lateinit var barcodeScannerView: DecoratedBarcodeView + private lateinit var firstEditText: TextInputEditText + private lateinit var secondEditText: TextInputEditText + private lateinit var imageView: ImageView + private lateinit var viewModel: CompareViewModel + + private var mFocused: Int = R.id.editText + + private val callback = object : BarcodeCallback { + override fun barcodeResult(result: BarcodeResult) { + barcodeScannerView.pause() + + result.text?.let { + view.findViewById(mFocused).setText(it) + mFocused = if (mFocused == R.id.editText) R.id.editText2 else R.id.editText + view.findViewById(mFocused).requestFocus() + } + + barcodeScannerView.resume() + } + + + override fun possibleResultPoints(resultPoints: MutableList?) {} + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + viewModel = ViewModelProvider(this)[CompareViewModel::class.java] + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.activity_compare, container, false).also { view = it } + } + + override fun onStart() { + super.onStart() + + imageView = view.findViewById(R.id.imageView) + firstEditText = view.findViewById(R.id.editText) + secondEditText = view.findViewById(R.id.editText2) + barcodeScannerView = view.findViewById(R.id.zxing_barcode_scanner) +// clearButton = view.findViewById(R.id.clearButton1) + + firstEditText.setOnClickListener { mFocused = R.id.editText } + secondEditText.setOnClickListener { mFocused = R.id.editText2 } + + val watcher: TextWatcher = object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + override fun afterTextChanged(s: Editable?) { + updateImageView() + } + } + + firstEditText.addTextChangedListener(watcher) + secondEditText.addTextChangedListener(watcher) + + val savedMode = getSavedMode() + viewModel.setMode(savedMode) + + setupBarcodeScanner() + setupRadioGroup() + setupEditTextListeners() + setupImageViewListener() + updateImageView() + + (activity as AppCompatActivity).supportActionBar?.title = "Compare Barcodes" + } + + private fun setupBarcodeScanner() { + barcodeScannerView.barcodeView.cameraSettings.isContinuousFocusEnabled = true + barcodeScannerView.barcodeView.cameraSettings.isBarcodeSceneModeEnabled = true + barcodeScannerView.decodeContinuous(callback) + } + + + private fun saveMode(mode: CompareViewModel.Mode) { + val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE) ?: return + with(sharedPref.edit()) { + putString("SAVED_MODE", mode.name) + apply() + } +} + + private fun getSavedMode(): CompareViewModel.Mode { + val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE) + val modeName = sharedPref?.getString("SAVED_MODE", CompareViewModel.Mode.Matches.name) + return CompareViewModel.Mode.valueOf(modeName ?: CompareViewModel.Mode.Matches.name) + } + + + private fun setupRadioGroup() { + val radioGroup = view.findViewById(R.id.compare_radio_group) + + // Set initial checked state based on saved preferences + val savedMode = getSavedMode() // Implement this method to read from SharedPreferences + val initialCheckId = if (savedMode == CompareViewModel.Mode.Contains) R.id.radioButton_contains else R.id.radioButton_matches + radioGroup.check(initialCheckId) + + // Listen for changes and save to preferences + radioGroup.setOnCheckedChangeListener { _, checkedId -> + val mode = if (checkedId == R.id.radioButton_contains) CompareViewModel.Mode.Contains else CompareViewModel.Mode.Matches + viewModel.setMode(mode) + Log.d("CompareFragment", "Mode changed to: $mode") + saveMode(mode) + updateImageView() // Force update view + } + } + + private fun setupEditTextListeners() { + val textWatcher = object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(s: Editable?) { + updateImageView() // Update the ImageView based on the current text + } + } + + firstEditText.addTextChangedListener(textWatcher) + secondEditText.addTextChangedListener(textWatcher) + } + + private fun setupImageViewListener() { + imageView.setOnClickListener { + firstEditText.text?.clear() + secondEditText.text?.clear() + imageView.visibility = View.INVISIBLE + } + } + + private fun updateImageView() { + val firstText = firstEditText.text?.toString() ?: "" + val secondText = secondEditText.text?.toString() ?: "" + + if (firstText.isNotEmpty() && secondText.isNotEmpty()) { + val match = when (viewModel.getMode()) { + CompareViewModel.Mode.Contains -> firstText.contains(secondText) || secondText.contains(firstText) + CompareViewModel.Mode.Matches -> firstText == secondText + } + imageView.setImageResource(if (match) R.drawable.ic_checkbox_marked_circle else R.drawable.ic_alpha_x_circle) + imageView.visibility = View.VISIBLE + } else { + imageView.visibility = View.INVISIBLE + } + } + + + override fun onResume() { + super.onResume() + barcodeScannerView.resume() + } + + override fun onPause() { + super.onPause() + barcodeScannerView.pause() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/phenoapps/verify/CustomAdapter.java b/app/src/main/java/org/phenoapps/verify/CustomAdapter.java new file mode 100644 index 0000000..9f989a8 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/CustomAdapter.java @@ -0,0 +1,65 @@ +package org.phenoapps.verify; + + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import java.util.ArrayList; + +public class CustomAdapter extends RecyclerView.Adapter{ + + + ArrayList values; + boolean auxValues = false; + + public static class ViewHolder extends RecyclerView.ViewHolder { + private final TextView textView; + + public ViewHolder(View view) { + super(view); + // Define click listener for the ViewHolder's View + + textView = (TextView) view.findViewById(R.id.textView_item); + } + + public TextView getTextView() { + return textView; + } + } + + public void setAuxValues(boolean auxValues) { + this.auxValues = auxValues; + } + + public CustomAdapter(ArrayList fieldValues){ + this.values = fieldValues; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.value_item, parent, false); + + return new ViewHolder(view); + } + + + + @Override + public void onBindViewHolder(@NonNull CustomAdapter.ViewHolder holder, int position) { + ValueModel value = values.get(position); + if(value.getAuxValue() && !this.auxValues){ + return; + } + holder.getTextView().setText( value.getPrefix() +" : "+value.getValue()); + } + + @Override + public int getItemCount() { + return values.size(); + } +} diff --git a/app/src/main/java/org/phenoapps/verify/HomeFragment.java b/app/src/main/java/org/phenoapps/verify/HomeFragment.java new file mode 100644 index 0000000..abe5d55 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/HomeFragment.java @@ -0,0 +1,714 @@ +package org.phenoapps.verify; + +import static androidx.core.app.ActivityCompat.startActivityForResult; + +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteStatement; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.preference.PreferenceManager; +import android.text.InputType; +import android.text.method.ScrollingMovementMethod; +import android.util.Log; +import android.util.SparseArray; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import org.phenoapps.verify.ViewModel.HomeViewModel; +import org.phenoapps.verify.utilities.FileExport; +import org.phenoapps.verify.utilities.IntentHelper; +import org.phenoapps.verify.utilities.RingUtility; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashSet; +import java.util.Locale; + +public class HomeFragment extends Fragment implements RingUtility, IntentHelper { + + + final static public String line_separator = System.getProperty("line.separator"); + + private SharedPreferences.OnSharedPreferenceChangeListener mPrefListener; + + //global variable to track matching order + private int mMatchingOrder; + //pair mode vars + private String mFileName = ""; + + private Toolbar navigationToolBar; + + private RecyclerView valueView; + + private int selectedIndex = -1; // -1 means no item is selected + private ArrayAdapter idAdapter; + + private CustomAdapter valuesAdapter; + private FileExport exportUtility; + + private HomeViewModel homeViewModel; + + private View view; + private Context context; + private Activity activity; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + PreferenceManager.setDefaultValues(getActivity(), R.xml.preferences, false); + + } + + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + this.view = view; + context = getContext(); + activity = getActivity(); + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + + valuesAdapter = new CustomAdapter(new ArrayList()); + + if (sharedPref.getBoolean(SettingsFragment.AUX_INFO, false)) { + valuesAdapter.setAuxValues(true); + } else { + valuesAdapter.setAuxValues(false); + } + + mPrefListener = (sharedPreferences, key) -> { + if (SettingsFragment.AUX_INFO.equals(key)) { + if (sharedPreferences.getBoolean(SettingsFragment.AUX_INFO, false)) { + valuesAdapter.setAuxValues(true); + } else { + valuesAdapter.setAuxValues(false); + } + } else if (SettingsFragment.AUDIO_ENABLED.equals(key)) { + boolean audioEnabled = sharedPreferences.getBoolean(SettingsFragment.AUDIO_ENABLED, true); + // Do something with the audioEnabled variable if needed + } + }; + + sharedPref.registerOnSharedPreferenceChangeListener(mPrefListener); + + + if (!sharedPref.getBoolean("onlyLoadTutorialOnce", false)) { + launchIntro(); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putBoolean("onlyLoadTutorialOnce", true); + editor.apply(); + } else { + boolean tutorialMode = sharedPref.getBoolean(SettingsFragment.TUTORIAL_MODE, false); + + if (tutorialMode) + launchIntro(); + } + + mFileName = sharedPref.getString(SettingsFragment.FILE_NAME, ""); + + ActivityCompat.requestPermissions(activity, VerifyConstants.permissions, VerifyConstants.PERM_REQ); + + mMatchingOrder = 0; + + initializeUIVariables(); + + homeViewModel = new HomeViewModel(activity); + + homeViewModel.loadSQLToLocal(activity); + buildListView(); + + if (homeViewModel.getmListId() != null) { + HashSet ids = homeViewModel.updateCheckedItems(); + updateTable(ids); + } + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + + return inflater.inflate(R.layout.fragment_home, container, false); + } + + @Nullable + private ActionBar getSupportActionBar() { + ActionBar actionBar = null; + if (activity instanceof AppCompatActivity) { + AppCompatActivity activity = (AppCompatActivity) getActivity(); + actionBar = activity.getSupportActionBar(); + } + return actionBar; + } + + private void initializeUIVariables() { + + if (getSupportActionBar() != null){ + getSupportActionBar().setTitle("CheckList"); + getSupportActionBar().getThemedContext(); + getSupportActionBar().setHomeButtonEnabled(true); + } + + final EditText scannerTextView = ((EditText) view.findViewById(R.id.scannerTextView)); +// scannerTextView.setSelectAllOnFocus(true); + scannerTextView.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + + if (event.getAction() == KeyEvent.ACTION_DOWN) { + if (keyCode == KeyEvent.KEYCODE_ENTER) { + checkScannedItem(); + } + } + return false; + } + }); + + ListView idTable = ((ListView) view.findViewById(R.id.idTable)); + idTable.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE); + idTable.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + selectedIndex = position; // Update the selected index + idAdapter.notifyDataSetChanged(); // Notify adapter to refresh the view + Log.d("EditText", "onItemClick: "+((TextView) view).getText().toString()); + scannerTextView.setText(((TextView) view).getText().toString()); + scannerTextView.setSelection(scannerTextView.getText().length()); + scannerTextView.requestFocus(); + scannerTextView.selectAll(); + checkScannedItem(); + } + }); + + idTable.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { +//get app settings + insertNoteIntoDb(((TextView) view).getText().toString()); + return true; + } + }); + + valueView = (RecyclerView) view.findViewById(R.id.valueView); + valueView.setLayoutManager(new LinearLayoutManager(context)); + valueView.setAdapter(valuesAdapter); + + view.findViewById(org.phenoapps.verify.R.id.clearButton).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + scannerTextView.setText(""); + } + }); + } + + private synchronized void checkScannedItem() { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + + String scannedId = ((EditText) view.findViewById(R.id.scannerTextView)).getText().toString(); + + if (!scannedId.isEmpty() && homeViewModel.getmIds() != null && homeViewModel.getmIds().size() > 0) { + exertModeFunction(scannedId); + ArrayList values = homeViewModel.getData(scannedId); + + if (values.size() > 0) { + valuesAdapter.values = values; + valuesAdapter.notifyDataSetChanged(); + } else { + clearRecyclerViews(); + if (scanMode != 2) { + this.ringNotification(false); + } + } + } else { + clearRecyclerViews(); + } + } + + private void clearRecyclerViews() { + valuesAdapter.values.clear(); + valuesAdapter.notifyDataSetChanged(); + } + + + private synchronized void insertNoteIntoDb(@NonNull final String id) { + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle("Enter a note for the given item."); + final EditText input = new EditText(context); + input.setInputType(InputType.TYPE_CLASS_TEXT); + builder.setView(input); + + builder.setPositiveButton("Save", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String value = input.getText().toString(); + if (!value.isEmpty()) { + homeViewModel.updateDb(value, id); + } + } + }); + + builder.show(); + } + + private synchronized void exertModeFunction(@NonNull String id) { + + //get app settings + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + +// TextView textView = view.findViewById(R.id.valueView); + if (scanMode == 0 ) { //default mode + mMatchingOrder = 0; + this.ringNotification(homeViewModel.checkIdExists(id)); + + } else if (scanMode == 1) { //order mode + final int tableIndex = getTableIndexById(id); + + if (tableIndex != -1) { + if (mMatchingOrder == tableIndex) { + mMatchingOrder++; + Toast.makeText(context, "Order matches id: " + id + " at index: " + tableIndex, Toast.LENGTH_SHORT).show(); + this.ringNotification(true); + } else { + Toast.makeText(context, "Scanning out of order!", Toast.LENGTH_SHORT).show(); + this.ringNotification(false); + } + } + } else if (scanMode == 2) { //filter mode, delete rows with given id + + mMatchingOrder = 0; + homeViewModel.executeDelete(id); + updateFilteredArrayAdapter(id); + + } else if (scanMode == 3) { //if color mode, update the db to highlight the item + + mMatchingOrder = 0; + homeViewModel.executeUpdate(id); + } else if (scanMode == 4) { //pair mode + + mMatchingOrder = 0; + + String mPairCol = homeViewModel.getmPairCol(); + + if (mPairCol != null) { + + String mNextPairVal = homeViewModel.getmNextPairVal(); + + //if next pair id is waiting, check if it matches scanned id and reset mode + String mNextPariVal = homeViewModel.getmNextPairVal(); + if (mNextPairVal != null) { + if (mNextPairVal.equals(id)) { + this.ringNotification(true); + Toast.makeText(context, "Scanned paired item: " + id, Toast.LENGTH_SHORT).show(); + } + homeViewModel.setmNextPairVal(null); + } else { //otherwise query for the current id's pair + homeViewModel.executeScan(id); + } + } + } + //always update user and datetime + final Calendar c = Calendar.getInstance(); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefault()); + + if (homeViewModel.getSqlUpdateUserAndDate() != null) { //no db yet + String name = sharedPref.getString(SettingsFragment.NAME, ""); + homeViewModel.executeUserUpdate(name, sdf.format(c.getTime()), id); + } + + HashSet ids = homeViewModel.updateCheckedItems(); + updateTable(ids); + } + + private void updateTable(HashSet ids){ + ListView idTable = (ListView) view.findViewById(org.phenoapps.verify.R.id.idTable); + for (int position = 0; position < idTable.getCount(); position++) { + + final String id = (idTable.getItemAtPosition(position)).toString(); + + if (ids.contains(id)) { + idTable.setItemChecked(position, true); + } else idTable.setItemChecked(position, false); + } + } + + //returns index of table with identifier = id, returns -1 if not found + private int getTableIndexById(String id) { + + ListView idTable = (ListView) view.findViewById(org.phenoapps.verify.R.id.idTable); + final int size = idTable.getAdapter().getCount(); + int ret = -1; + for (int i = 0; i < size; i++) { + final String temp = (String) idTable.getAdapter().getItem(i); + if (temp.equals(id)) { + ret = i; + break; //break out of for-loop early + } + } + + return ret; + } + + private void updateFilteredArrayAdapter(String id) { + ListView idTable = (ListView) view.findViewById(R.id.idTable); + + // Save the top item's index and top position + int index = idTable.getFirstVisiblePosition(); + View v = idTable.getChildAt(0); + int top = (v == null) ? 0 : (v.getTop() - idTable.getPaddingTop()); + + // Update id table array adapter + ArrayAdapter updatedAdapter = new ArrayAdapter<>(context, R.layout.row); + int oldSize = idTable.getAdapter().getCount(); + for (int i = 0; i < oldSize; i++) { + String temp = (String) idTable.getAdapter().getItem(i); + if (!temp.equals(id)) { + updatedAdapter.add(temp); + } + } + idTable.setAdapter(updatedAdapter); + + // Restore the list view's position + idTable.setSelectionFromTop(index, top); + } + + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(org.phenoapps.verify.R.menu.activity_main_toolbar, menu); + } + + @Override + final public boolean onOptionsItemSelected(MenuItem item) { + int actionCamera = R.id.action_camera; + int actionImport = R.id.action_import; + int actionExport = R.id.action_export; + + if (item.getItemId() == actionImport){ + final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + final int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + final Intent i; + File verifyDirectory = new File(context.getExternalFilesDir(null), "/Verify"); + + File[] files = verifyDirectory.listFiles(); + + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle("Select files from?"); + builder.setPositiveButton("Storage", + new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int id) + { + Intent i; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + i = new Intent(Intent.ACTION_OPEN_DOCUMENT); + }else{ + i = new Intent(Intent.ACTION_GET_CONTENT); + } + i.setType("*/*"); + startActivityForResult(Intent.createChooser(i, "Choose file to import."), VerifyConstants.DEFAULT_CONTENT_REQ); + } + }); + + builder.setNegativeButton("Verify Directory", + new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int id) + { + + AlertDialog.Builder fileBuilder = new AlertDialog.Builder(context); + fileBuilder.setTitle("Select the sample file"); + final int[] checkedItem = {-1}; + String[] listItems = verifyDirectory.list(); + Log.d("listItems", "onClick: "+listItems); + fileBuilder.setSingleChoiceItems(listItems, checkedItem[0],(fileDialog, which) -> { + checkedItem[0] = which; + + Intent i = new Intent(context, LoaderDBActivity.class); + i.setData(Uri.fromFile(files[which])); + startActivityForResult(i, VerifyConstants.LOADER_INTENT_REQ); + fileDialog.dismiss(); + }); + + fileBuilder.show(); + } + }); + builder.show(); + } else if(item.getItemId() == actionCamera){ + final Intent cameraIntent = new Intent(context, ScanActivity.class); + startActivityForResult(cameraIntent, VerifyConstants.CAMERA_INTENT_REQ); + } else if (item.getItemId() == actionExport) { + exportUtility = new FileExport(this.activity,this.mFileName, this.homeViewModel.getmDbHelper()); + exportUtility.askUserExportFileName(this); + } else { + return super.onOptionsItemSelected(item); + } + return true; + } + + @Override + final public void onActivityResult(int requestCode, int resultCode, Intent intent) { + + super.onActivityResult(requestCode, resultCode, intent); + + if (resultCode == Activity.RESULT_OK) { + + if (intent != null) { + switch (requestCode) { + + case VerifyConstants.PICK_CUSTOM_DEST: + exportUtility.writeToExportPath(intent.getData()); + break; + case VerifyConstants.DEFAULT_CONTENT_REQ: + Intent i = new Intent(context, LoaderDBActivity.class); + i.setData(intent.getData()); + startActivityForResult(i, VerifyConstants.LOADER_INTENT_REQ); + break; + case VerifyConstants.LOADER_INTENT_REQ: + + homeViewModel.setmListId(null); + homeViewModel.setmPairCol(null); + mFileName = ""; + + if (intent.hasExtra(VerifyConstants.FILE_NAME)) + mFileName = intent.getStringExtra(VerifyConstants.FILE_NAME); + if (intent.hasExtra(VerifyConstants.LIST_ID_EXTRA)) + homeViewModel.setmListId(intent.getStringExtra(VerifyConstants.LIST_ID_EXTRA)); + if (intent.hasExtra(VerifyConstants.PAIR_COL_EXTRA)) + homeViewModel.setmPairCol(intent.getStringExtra(VerifyConstants.PAIR_COL_EXTRA)); + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + final SharedPreferences.Editor editor = sharedPref.edit(); + + int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + + String mPairCol = homeViewModel.getmPairCol(); + if (mPairCol != null) { + editor.putBoolean(SettingsFragment.DISABLE_PAIR, false); + if (scanMode != 4) showPairDialog(); + } else { + editor.putBoolean(SettingsFragment.DISABLE_PAIR, true); + } + + if (mPairCol == null && scanMode == 4) { + editor.putString(SettingsFragment.SCAN_MODE_LIST, "0"); + Toast.makeText(context, + "Switching to default mode, no pair ID found.", + Toast.LENGTH_SHORT).show(); + } + editor.putString(SettingsFragment.FILE_NAME, mFileName); + editor.putString(SettingsFragment.PAIR_NAME, mPairCol); + editor.putString(SettingsFragment.LIST_KEY_NAME, homeViewModel.getmListId()); + editor.apply(); + + clearListView(); + homeViewModel.loadSQLToLocal(activity); + HashSet ids = homeViewModel.updateCheckedItems(); + updateTable(ids); + refreshData(); + break; + } + + if (intent.hasExtra(VerifyConstants.CAMERA_RETURN_ID)) { + ((EditText) view.findViewById(org.phenoapps.verify.R.id.scannerTextView)) + .setText(intent.getStringExtra(VerifyConstants.CAMERA_RETURN_ID)); + checkScannedItem(); + } + } + } + } + + private void buildListView() { + ListView idTable = (ListView) view.findViewById(R.id.idTable); + + idAdapter = new ArrayAdapter(context, android.R.layout.simple_list_item_1, android.R.id.text1) { + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + View view = super.getView(position, convertView, parent); + TextView textView = view.findViewById(android.R.id.text1); + + // Here, apply the logic to determine if the item is selected + if (position == selectedIndex) { // Check if the current item is selected + textView.setBackgroundColor(ContextCompat.getColor(context, R.color.colorAccent)); + } else { + textView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)); + } + + return view; + } + }; + + // Add data to the adapter + int size = homeViewModel.getmIds().size(); + SparseArray mIds = homeViewModel.getmIds(); + for (int i = 0; i < size; i++) { + idAdapter.add(mIds.get(mIds.keyAt(i))); + } + idTable.setAdapter(idAdapter); + } + + + private void clearListView() { + + ListView idTable = (ListView) view.findViewById(org.phenoapps.verify.R.id.idTable); + final ArrayAdapter adapter = + new ArrayAdapter<>(context, org.phenoapps.verify.R.layout.row); + + idTable.setAdapter(adapter); + adapter.notifyDataSetChanged(); + } + + private void showPairDialog() { + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle("Pair column selected, would you like to switch to Pair mode?"); + + builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(SettingsFragment.SCAN_MODE_LIST, "4"); + editor.apply(); + } + }); + + builder.setNegativeButton("No thanks", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + + } + }); + + builder.show(); + } + + @Override + final public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + } + + private void launchIntro() { + + new Thread(new Runnable() { + @Override + public void run() { + + // Launch app intro + final Intent i = new Intent(context, IntroActivity.class); + + activity.runOnUiThread(new Runnable() { + @Override public void run() { + startActivity(i); + } + }); + + + } + }).start(); + } + + @Override + final public void onDestroy() { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + sharedPref.unregisterOnSharedPreferenceChangeListener(mPrefListener); + homeViewModel.getmDbHelper().close(); + super.onDestroy(); + } + + @Override + public void ringNotification(boolean success) { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + PreferenceManager.setDefaultValues(context, R.xml.preferences, false); + boolean audioEnabled = sharedPref.getBoolean(SettingsFragment.AUDIO_ENABLED, true); + + if (success) { + if (audioEnabled) { + playSound("plonk"); + } + } else { + // Optionally handle the failure case, such as playing a different sound + if (audioEnabled) { + playSound("error"); + } else { + Toast.makeText(context, "Scanned ID not found", Toast.LENGTH_SHORT).show(); + } + } + } + + private void playSound(String soundResourceName) { + try { + int resID = getResources().getIdentifier(soundResourceName, "raw", activity.getPackageName()); + MediaPlayer chimePlayer = MediaPlayer.create(context, resID); + chimePlayer.start(); + chimePlayer.setOnCompletionListener(MediaPlayer::release); + } catch (Exception e) { + Log.e("HomeFragment", "Error playing sound", e); + } + } + + + private void refreshData() { + homeViewModel.loadSQLToLocal(activity); // Reload data + buildListView(); // Rebuild the list view with new data + + // Optionally update any other parts of the UI that depend on the data + if (homeViewModel.getmListId() != null) { + HashSet ids = homeViewModel.updateCheckedItems(); + updateTable(ids); + } + } + + @Override + public void startIntent(Intent i) { + startActivityForResult(Intent.createChooser(i, "Choose folder to export file."), VerifyConstants.PICK_CUSTOM_DEST, null); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/phenoapps/verify/IdEntryContract.java b/app/src/main/java/org/phenoapps/verify/IdEntryContract.java index 22dc463..d342fe3 100644 --- a/app/src/main/java/org/phenoapps/verify/IdEntryContract.java +++ b/app/src/main/java/org/phenoapps/verify/IdEntryContract.java @@ -6,12 +6,12 @@ * Created by Chaney on 7/13/2017. */ -final class IdEntryContract { +public final class IdEntryContract { private IdEntryContract() {} - static class IdEntry implements BaseColumns { - static final String TABLE_NAME = "VERIFY"; + public static class IdEntry implements BaseColumns { + public static final String TABLE_NAME = "VERIFY"; static final String COLUMN_NAME_ID = "id"; static final String COLUMN_NAME_CHECKED = "checked"; static final String COLUMN_NAME_SCANNED = "scanned"; diff --git a/app/src/main/java/org/phenoapps/verify/IdEntryDbHelper.java b/app/src/main/java/org/phenoapps/verify/IdEntryDbHelper.java index 252bca1..3f18fdb 100644 --- a/app/src/main/java/org/phenoapps/verify/IdEntryDbHelper.java +++ b/app/src/main/java/org/phenoapps/verify/IdEntryDbHelper.java @@ -8,12 +8,12 @@ * Created by Chaney on 7/13/2017. */ -class IdEntryDbHelper extends SQLiteOpenHelper { +public class IdEntryDbHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 2; private static final String DATABASE_NAME = "IdEntryReader.db"; - IdEntryDbHelper(Context context) { + public IdEntryDbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } diff --git a/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java b/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java index 249f417..eada8d9 100644 --- a/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java +++ b/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java @@ -71,7 +71,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_load_file); if(getSupportActionBar() != null){ - getSupportActionBar().setTitle(null); + getSupportActionBar().setTitle("Import Data"); getSupportActionBar().getThemedContext(); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); diff --git a/app/src/main/java/org/phenoapps/verify/MainActivity.java b/app/src/main/java/org/phenoapps/verify/MainActivity.java index c9d424b..da7acd7 100644 --- a/app/src/main/java/org/phenoapps/verify/MainActivity.java +++ b/app/src/main/java/org/phenoapps/verify/MainActivity.java @@ -18,13 +18,26 @@ import android.preference.PreferenceManager; import androidx.annotation.NonNull; + +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.navigation.NavigationBarView; import com.google.android.material.navigation.NavigationView; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.ActionMenuView; +import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityCompat; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.navigation.NavController; +import androidx.navigation.NavDestination; +import androidx.navigation.Navigation; +import androidx.navigation.ui.AppBarConfiguration; +import androidx.navigation.ui.NavigationUI; + import android.text.InputType; import android.text.method.ScrollingMovementMethod; import android.util.Log; @@ -34,6 +47,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.AbsListView; import android.widget.AdapterView; @@ -58,101 +72,36 @@ public class MainActivity extends AppCompatActivity { - final static private String line_separator = System.getProperty("line.separator"); - - private IdEntryDbHelper mDbHelper; - - private SharedPreferences.OnSharedPreferenceChangeListener mPrefListener; - - //database prepared statements - private SQLiteStatement sqlUpdateNote; - private SQLiteStatement sqlDeleteId; - private SQLiteStatement sqlUpdateChecked; - private SQLiteStatement sqlUpdateUserAndDate; - - private SparseArray mIds; - - //Verify UI variables - private ActionBarDrawerToggle mDrawerToggle; - - //global variable to track matching order - private int mMatchingOrder; - - private String mListId; - - //pair mode vars - private String mPairCol; - private String mNextPairVal; - - private String mFileName = ""; + private static final long BACK_PRESS_INTERVAL = 2000; // 2 seconds + private long lastBackPressTime = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(org.phenoapps.verify.R.layout.activity_main); - - mIds = new SparseArray<>(); - - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - - final View auxInfo = findViewById(R.id.auxScrollView); - final View auxValue = findViewById(R.id.auxValueView); - - if (sharedPref.getBoolean(SettingsActivity.AUX_INFO, false)) { - auxInfo.setVisibility(View.VISIBLE); - auxValue.setVisibility(View.VISIBLE); - - } else { - auxInfo.setVisibility(View.GONE); - auxValue.setVisibility(View.GONE); - } - - mPrefListener = new SharedPreferences.OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - - if (sharedPreferences.getBoolean(SettingsActivity.AUX_INFO, false)) { - auxInfo.setVisibility(View.VISIBLE); - auxValue.setVisibility(View.VISIBLE); - } else { - auxInfo.setVisibility(View.GONE); - auxValue.setVisibility(View.GONE); - } - } - }; - - sharedPref.registerOnSharedPreferenceChangeListener(mPrefListener); + setContentView(R.layout.activity_main); - if (!sharedPref.getBoolean("onlyLoadTutorialOnce", false)) { - launchIntro(); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putBoolean("onlyLoadTutorialOnce", true); - editor.apply(); - } else { - boolean tutorialMode = sharedPref.getBoolean(SettingsActivity.TUTORIAL_MODE, false); - - if (tutorialMode) - launchIntro(); - } - - mFileName = sharedPref.getString(SettingsActivity.FILE_NAME, ""); - - ActivityCompat.requestPermissions(this, VerifyConstants.permissions, VerifyConstants.PERM_REQ); + BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_toolbar);; + NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); + NavigationUI.setupWithNavController(bottomNavigationView, navController); + } - mNextPairVal = null; - mMatchingOrder = 0; - mPairCol = null; - initializeUIVariables(); + @Override + final public void onPause() { + super.onPause(); + } - mDbHelper = new IdEntryDbHelper(this); - loadSQLToLocal(); + @Override + public boolean onSupportNavigateUp() { + NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); + return navController.navigateUp() || super.onSupportNavigateUp(); + } - if (mListId != null) - updateCheckedItems(); + public static void scanFile(Context ctx, File filePath) { + MediaScannerConnection.scanFile(ctx, new String[] { filePath.getAbsolutePath()}, null, null); } private void copyRawToVerify(File verifyDirectory, String fileName, int rawId) { @@ -180,994 +129,13 @@ private void copyRawToVerify(File verifyDirectory, String fileName, int rawId) { } } - public static void scanFile(Context ctx, File filePath) { - MediaScannerConnection.scanFile(ctx, new String[] { filePath.getAbsolutePath()}, null, null); - } - - private void prepareStatements() { - - final SQLiteDatabase db = mDbHelper.getWritableDatabase(); - try { - String updateNoteQuery = "UPDATE VERIFY SET note = ? WHERE " + mListId + " = ?"; - sqlUpdateNote = db.compileStatement(updateNoteQuery); - - String deleteIdQuery = "DELETE FROM VERIFY WHERE " + mListId + " = ?"; - sqlDeleteId = db.compileStatement(deleteIdQuery); - - String updateCheckedQuery = "UPDATE VERIFY SET color = 1 WHERE " + mListId + " = ?"; - sqlUpdateChecked = db.compileStatement(updateCheckedQuery); - - String updateUserAndDateQuery = - "UPDATE VERIFY SET user = ?, date = ?, scan_count = scan_count + 1 WHERE " + mListId + " = ?"; - sqlUpdateUserAndDate = db.compileStatement(updateUserAndDateQuery); - } catch(SQLiteException e) { - e.printStackTrace(); - } - } - - private void initializeUIVariables() { - - if (getSupportActionBar() != null){ - getSupportActionBar().setTitle(null); - getSupportActionBar().getThemedContext(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - } - - final NavigationView nvDrawer = (NavigationView) findViewById(R.id.nvView); - - // Setup drawer view - setupDrawerContent(nvDrawer); - setupDrawer(); - - final EditText scannerTextView = ((EditText) findViewById(R.id.scannerTextView)); - scannerTextView.setSelectAllOnFocus(true); - scannerTextView.setOnKeyListener(new View.OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - - if (event.getAction() == KeyEvent.ACTION_DOWN) { - if (keyCode == KeyEvent.KEYCODE_ENTER) { - checkScannedItem(); - } - } - return false; - } - }); - - ListView idTable = ((ListView) findViewById(R.id.idTable)); - idTable.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE); - idTable.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - scannerTextView.setText(((TextView) view).getText().toString()); - scannerTextView.setSelection(scannerTextView.getText().length()); - scannerTextView.requestFocus(); - scannerTextView.selectAll(); - checkScannedItem(); - } - }); - - idTable.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - //get app settings - insertNoteIntoDb(((TextView) view).getText().toString()); - return true; - } - }); - - TextView valueView = (TextView) findViewById(R.id.valueView); - valueView.setMovementMethod(new ScrollingMovementMethod()); - - findViewById(org.phenoapps.verify.R.id.clearButton).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - scannerTextView.setText(""); - } - }); - } - - private synchronized void checkScannedItem() { - - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); - int scanMode = Integer.valueOf(sharedPref.getString(SettingsActivity.SCAN_MODE_LIST, "-1")); - boolean displayAux = sharedPref.getBoolean(SettingsActivity.AUX_INFO, true); - - String scannedId = ((EditText) findViewById(org.phenoapps.verify.R.id.scannerTextView)) - .getText().toString(); - - if (mIds != null && mIds.size() > 0) { - //update database - exertModeFunction(scannedId); - - //view updated database - SQLiteDatabase db = mDbHelper.getReadableDatabase(); - - String table = IdEntryContract.IdEntry.TABLE_NAME; - String[] selectionArgs = new String[]{scannedId}; - Cursor cursor = db.query(table, null, mListId + "=?", selectionArgs, null, null, null); - - String[] headerTokens = cursor.getColumnNames(); - StringBuilder values = new StringBuilder(); - StringBuilder auxValues = new StringBuilder(); - if (cursor.moveToFirst()) { - for (String header : headerTokens) { - - if (!header.equals(mListId)) { - - final String val = cursor.getString( - cursor.getColumnIndexOrThrow(header) - ); - - if (header.equals("color") || header.equals("scan_count") || header.equals("date") - || header.equals("user") || header.equals("note")) { - if (header.equals("color")) continue; - else if (header.equals("scan_count")) auxValues.append("Number of scans"); - else if (header.equals("date")) auxValues.append("Date"); - else auxValues.append(header); - auxValues.append(" : "); - if (val != null) auxValues.append(val); - auxValues.append(line_separator); - } else { - values.append(header); - values.append(" : "); - if (val != null) values.append(val); - values.append(line_separator); - } - } - } - cursor.close(); - ((TextView) findViewById(org.phenoapps.verify.R.id.valueView)).setText(values.toString()); - ((TextView) findViewById(R.id.auxValueView)).setText(auxValues.toString()); - ((EditText) findViewById(R.id.scannerTextView)).setText(""); - } else { - if (scanMode != 2) { - ringNotification(false); - } - } - } - } - - private Boolean checkIdExists(String id) { - SQLiteDatabase db = mDbHelper.getReadableDatabase(); - - final String table = IdEntryContract.IdEntry.TABLE_NAME; - final String[] selectionArgs = new String[] { id }; - final Cursor cursor = db.query(table, null, mListId + "=?", selectionArgs, null, null, null); - - if (cursor.moveToFirst()) { - cursor.close(); - return true; - } else { - cursor.close(); - return false; - } - } - - private synchronized void insertNoteIntoDb(@NonNull final String id) { - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Enter a note for the given item."); - final EditText input = new EditText(this); - input.setInputType(InputType.TYPE_CLASS_TEXT); - builder.setView(input); - - builder.setPositiveButton("Save", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String value = input.getText().toString(); - if (!value.isEmpty()) { - - final SQLiteDatabase db = mDbHelper.getWritableDatabase(); - - if (sqlUpdateNote != null) { - sqlUpdateNote.bindAllArgsAsStrings(new String[]{ - value, id - }); - sqlUpdateNote.executeUpdateDelete(); - } - } - } - }); - - builder.show(); - } - - private synchronized void exertModeFunction(@NonNull String id) { - - //get app settings - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); - int scanMode = Integer.valueOf(sharedPref.getString(SettingsActivity.SCAN_MODE_LIST, "-1")); - - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - - if (scanMode == 0 ) { //default mode - mMatchingOrder = 0; - ringNotification(checkIdExists(id)); - - } else if (scanMode == 1) { //order mode - final int tableIndex = getTableIndexById(id); - - if (tableIndex != -1) { - if (mMatchingOrder == tableIndex) { - mMatchingOrder++; - Toast.makeText(this, "Order matches id: " + id + " at index: " + tableIndex, Toast.LENGTH_SHORT).show(); - ringNotification(true); - } else { - Toast.makeText(this, "Scanning out of order!", Toast.LENGTH_SHORT).show(); - ringNotification(false); - } - } - } else if (scanMode == 2) { //filter mode, delete rows with given id - - mMatchingOrder = 0; - if (sqlDeleteId != null) { - sqlDeleteId.bindAllArgsAsStrings(new String[]{id}); - sqlDeleteId.executeUpdateDelete(); - } - updateFilteredArrayAdapter(id); - - } else if (scanMode == 3) { //if color mode, update the db to highlight the item - - mMatchingOrder = 0; - if (sqlUpdateChecked != null) { - sqlUpdateChecked.bindAllArgsAsStrings(new String[]{id}); - sqlUpdateChecked.executeUpdateDelete(); - } - } else if (scanMode == 4) { //pair mode - - mMatchingOrder = 0; - - if (mPairCol != null) { - - //if next pair id is waiting, check if it matches scanned id and reset mode - if (mNextPairVal != null) { - if (mNextPairVal.equals(id)) { - ringNotification(true); - Toast.makeText(this, "Scanned paired item: " + id, Toast.LENGTH_SHORT).show(); - } - mNextPairVal = null; - } else { //otherwise query for the current id's pair - String table = IdEntryContract.IdEntry.TABLE_NAME; - String[] columnsNames = new String[] { mPairCol }; - String selection = mListId + "=?"; - String[] selectionArgs = { id }; - Cursor cursor = db.query(table, columnsNames, selection, selectionArgs, null, null, null); - if (cursor.moveToFirst()) { - mNextPairVal = cursor.getString( - cursor.getColumnIndexOrThrow(mPairCol) - ); - } else mNextPairVal = null; - cursor.close(); - } - } - } - //always update user and datetime - final Calendar c = Calendar.getInstance(); - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefault()); - - if (sqlUpdateUserAndDate != null) { //no db yet - String firstName = sharedPref.getString(SettingsActivity.FIRST_NAME, ""); - String lastName = sharedPref.getString(SettingsActivity.LAST_NAME, ""); - sqlUpdateUserAndDate.bindAllArgsAsStrings(new String[]{ - firstName + " " + lastName, - sdf.format(c.getTime()), - id - }); - sqlUpdateUserAndDate.executeUpdateDelete(); - } - - updateCheckedItems(); - } - - private synchronized void updateCheckedItems() { - - final SQLiteDatabase db = mDbHelper.getReadableDatabase(); - - //list of ideas to populate and update the view with - final HashSet ids = new HashSet<>(); - - final String table = IdEntryContract.IdEntry.TABLE_NAME; - final String[] columns = new String[] { mListId }; - final String selection = "color = 1"; - - try { - final Cursor cursor = db.query(table, columns, selection, null, null, null, null); - if (cursor.moveToFirst()) { - do { - String id = cursor.getString( - cursor.getColumnIndexOrThrow(mListId) - ); - - ids.add(id); - } while (cursor.moveToNext()); - } - cursor.close(); - } catch (SQLiteException e) { - e.printStackTrace(); - } - ListView idTable = (ListView) findViewById(org.phenoapps.verify.R.id.idTable); - for (int position = 0; position < idTable.getCount(); position++) { - - final String id = (idTable.getItemAtPosition(position)).toString(); - - if (ids.contains(id)) { - idTable.setItemChecked(position, true); - } else idTable.setItemChecked(position, false); - } - } - - private synchronized void loadSQLToLocal() { - - mIds = new SparseArray<>(); - - mDbHelper = new IdEntryDbHelper(this); - - final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); - mListId = sharedPref.getString(SettingsActivity.LIST_KEY_NAME, null); - mPairCol = sharedPref.getString(SettingsActivity.PAIR_NAME, null); - - if (mListId != null) { - prepareStatements(); - loadBarcodes(); - buildListView(); - } - } - - private void loadBarcodes() { - - SQLiteDatabase db = mDbHelper.getReadableDatabase(); - try { - final String table = IdEntryContract.IdEntry.TABLE_NAME; - final Cursor cursor = db.query(table, null, null, null, null, null, null); - - if (cursor.moveToFirst()) { - do { - final String[] headers = cursor.getColumnNames(); - for (String header : headers) { - - final String val = cursor.getString( - cursor.getColumnIndexOrThrow(header) - ); - - if (header.equals(mListId)) { - mIds.append(mIds.size(), val); - } - } - } while (cursor.moveToNext()); - } - cursor.close(); - - } catch (SQLiteException e) { - e.printStackTrace(); - } - } - - private synchronized void askUserExportFileName() { - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Choose name for exported file."); - final EditText input = new EditText(this); - - final Calendar c = Calendar.getInstance(); - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); - - int lastDot = mFileName.lastIndexOf('.'); - if (lastDot != -1) { - mFileName = mFileName.substring(0, lastDot); - } - input.setText("Verify_"+ sdf.format(c.getTime())); - input.setInputType(InputType.TYPE_CLASS_TEXT); - builder.setView(input); - - builder.setPositiveButton("Export", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int which) { - String value = input.getText().toString(); - mFileName = value; - final Intent i; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { - i = new Intent(Intent.ACTION_CREATE_DOCUMENT); - i.setType("*/*"); - i.putExtra(Intent.EXTRA_TITLE, value+".csv"); - startActivityForResult(Intent.createChooser(i, "Choose folder to export file."), VerifyConstants.PICK_CUSTOM_DEST); - }else{ - writeToExportPath(); - } - } - }); - builder.show(); - } - - public void writeToExportPath(){ - String value = mFileName; - - if (!value.isEmpty()) { - if (isExternalStorageWritable()) { - try { - File verifyDirectory = new File(Environment.getExternalStorageDirectory().getPath() + "/Verify"); - final File output = new File(verifyDirectory, value + ".csv"); - final FileOutputStream fstream = new FileOutputStream(output); - final SQLiteDatabase db = mDbHelper.getReadableDatabase(); - final String table = IdEntryContract.IdEntry.TABLE_NAME; - final Cursor cursor = db.query(table, null, null, null, null, null, null); - //final Cursor cursor = db.rawQuery("SElECT * FROM VERIFY", null); - - //first write header line - final String[] headers = cursor.getColumnNames(); - for (int i = 0; i < headers.length; i++) { - if (i != 0) fstream.write(",".getBytes()); - fstream.write(headers[i].getBytes()); - } - fstream.write(line_separator.getBytes()); - //populate text file with current database values - if (cursor.moveToFirst()) { - do { - for (int i = 0; i < headers.length; i++) { - if (i != 0) fstream.write(",".getBytes()); - final String val = cursor.getString( - cursor.getColumnIndexOrThrow(headers[i]) - ); - if (val == null) fstream.write("null".getBytes()); - else fstream.write(val.getBytes()); - } - fstream.write(line_separator.getBytes()); - } while (cursor.moveToNext()); - } - - cursor.close(); - fstream.flush(); - fstream.close(); - scanFile(MainActivity.this, output); - /*MediaScannerConnection.scanFile(MainActivity.this, new String[] {output.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() { - @Override - public void onScanCompleted(String path, Uri uri) { - Log.v("scan complete", path); - } - });*/ - }catch (NullPointerException npe){ - npe.printStackTrace(); - Toast.makeText(this, "Error in opening the Specified file", Toast.LENGTH_LONG).show(); - } - catch (SQLiteException e) { - e.printStackTrace(); - Toast.makeText(MainActivity.this, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException io) { - io.printStackTrace(); - } - } else { - Toast.makeText(MainActivity.this, - "External storage not writable.", Toast.LENGTH_SHORT).show(); - } - } else { - Toast.makeText(MainActivity.this, - "Must enter a file name.", Toast.LENGTH_SHORT).show(); - } - } - - public void writeToExportPath(Uri uri){ - - String value = mFileName; - - if (uri == null){ - Toast.makeText(this, "Unable to open the Specified file", Toast.LENGTH_LONG).show(); - return; - } - - if (!value.isEmpty()) { - if (isExternalStorageWritable()) { - try { - final File output = new File(uri.getPath()); - final OutputStream fstream = getContentResolver().openOutputStream(uri); - final SQLiteDatabase db = mDbHelper.getReadableDatabase(); - final String table = IdEntryContract.IdEntry.TABLE_NAME; - final Cursor cursor = db.query(table, null, null, null, null, null, null); - //final Cursor cursor = db.rawQuery("SElECT * FROM VERIFY", null); - - //first write header line - final String[] headers = cursor.getColumnNames(); - for (int i = 0; i < headers.length; i++) { - if (i != 0) fstream.write(",".getBytes()); - fstream.write(headers[i].getBytes()); - } - fstream.write(line_separator.getBytes()); - //populate text file with current database values - if (cursor.moveToFirst()) { - do { - for (int i = 0; i < headers.length; i++) { - if (i != 0) fstream.write(",".getBytes()); - final String val = cursor.getString( - cursor.getColumnIndexOrThrow(headers[i]) - ); - if (val == null) fstream.write("null".getBytes()); - else fstream.write(val.getBytes()); - } - fstream.write(line_separator.getBytes()); - } while (cursor.moveToNext()); - } - - cursor.close(); - fstream.flush(); - fstream.close(); - scanFile(MainActivity.this, output); - /*MediaScannerConnection.scanFile(MainActivity.this, new String[] {output.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() { - @Override - public void onScanCompleted(String path, Uri uri) { - Log.v("scan complete", path); - } - });*/ - }catch (NullPointerException npe){ - npe.printStackTrace(); - Toast.makeText(this, "Error in opening the Specified file", Toast.LENGTH_LONG).show(); - } - catch (SQLiteException e) { - e.printStackTrace(); - Toast.makeText(MainActivity.this, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException io) { - io.printStackTrace(); - } - } else { - Toast.makeText(MainActivity.this, - "External storage not writable.", Toast.LENGTH_SHORT).show(); - } - } else { - Toast.makeText(MainActivity.this, - "Must enter a file name.", Toast.LENGTH_SHORT).show(); - } - } - - //returns index of table with identifier = id, returns -1 if not found - private int getTableIndexById(String id) { - - ListView idTable = (ListView) findViewById(org.phenoapps.verify.R.id.idTable); - final int size = idTable.getAdapter().getCount(); - int ret = -1; - for (int i = 0; i < size; i++) { - final String temp = (String) idTable.getAdapter().getItem(i); - if (temp.equals(id)) { - ret = i; - break; //break out of for-loop early - } - } - - return ret; - } - - private void updateFilteredArrayAdapter(String id) { - - ListView idTable = (ListView) findViewById(org.phenoapps.verify.R.id.idTable); - //update id table array adapter - final ArrayAdapter updatedAdapter = new ArrayAdapter<>(this, org.phenoapps.verify.R.layout.row); - final int oldSize = idTable.getAdapter().getCount(); - - for (int i = 0; i < oldSize; i++) { - final String temp = (String) idTable.getAdapter().getItem(i); - if (!temp.equals(id)) updatedAdapter.add(temp); - } - idTable.setAdapter(updatedAdapter); - } - - private void ringNotification(boolean success) { - - final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - final boolean audioEnabled = sharedPref.getBoolean(SettingsActivity.AUDIO_ENABLED, true); - - if(success) { //ID found - if(audioEnabled) { - if (success) { - try { - int resID = getResources().getIdentifier("plonk", "raw", getPackageName()); - MediaPlayer chimePlayer = MediaPlayer.create(MainActivity.this, resID); - chimePlayer.start(); - - chimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - public void onCompletion(MediaPlayer mp) { - mp.release(); - } - }); - } catch (Exception ignore) { - } - } - } - } - - if(!success) { //ID not found - ((TextView) findViewById(org.phenoapps.verify.R.id.valueView)).setText(""); - - if (audioEnabled) { - if(!success) { - try { - int resID = getResources().getIdentifier("error", "raw", getPackageName()); - MediaPlayer chimePlayer = MediaPlayer.create(MainActivity.this, resID); - chimePlayer.start(); - - chimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - public void onCompletion(MediaPlayer mp) { - mp.release(); - } - }); - } catch (Exception ignore) { - } - } - } else { - if (!success) { - Toast.makeText(this, "Scanned ID not found", Toast.LENGTH_SHORT).show(); - } - } - } - } - - @Override - final public boolean onCreateOptionsMenu(Menu m) { - - final MenuInflater inflater = getMenuInflater(); - inflater.inflate(org.phenoapps.verify.R.menu.activity_main_toolbar, m); - return true; - } - - @Override - final public boolean onOptionsItemSelected(MenuItem item) { - DrawerLayout dl = (DrawerLayout) findViewById(R.id.drawer_layout); - int actionCamera = R.id.action_camera; - int actionCompare = R.id.action_compare; - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - - if (item.getItemId() == android.R.id.home){ - dl.openDrawer(GravityCompat.START); - } - else if(item.getItemId() == actionCamera){ - final Intent cameraIntent = new Intent(this, ScanActivity.class); - startActivityForResult(cameraIntent, VerifyConstants.CAMERA_INTENT_REQ); - } - else if(item.getItemId() == actionCompare){ - final Intent compareIntent = new Intent(MainActivity.this, CompareActivity.class); - runOnUiThread(new Runnable() { - @Override public void run() { - startActivity(compareIntent); - } - }); - } - else{ - return super.onOptionsItemSelected(item); - } - return true; - } - - @Override - final protected void onActivityResult(int requestCode, int resultCode, Intent intent) { - - super.onActivityResult(requestCode, resultCode, intent); - - if (resultCode == RESULT_OK) { - - if (intent != null) { - switch (requestCode) { - case VerifyConstants.PICK_CUSTOM_DEST: - writeToExportPath(intent.getData()); - break; - case VerifyConstants.DEFAULT_CONTENT_REQ: - Intent i = new Intent(this, LoaderDBActivity.class); - i.setData(intent.getData()); - startActivityForResult(i, VerifyConstants.LOADER_INTENT_REQ); - break; - case VerifyConstants.LOADER_INTENT_REQ: - - mListId = null; - mPairCol = null; - mFileName = ""; - - if (intent.hasExtra(VerifyConstants.FILE_NAME)) - mFileName = intent.getStringExtra(VerifyConstants.FILE_NAME); - if (intent.hasExtra(VerifyConstants.LIST_ID_EXTRA)) - mListId = intent.getStringExtra(VerifyConstants.LIST_ID_EXTRA); - if (intent.hasExtra(VerifyConstants.PAIR_COL_EXTRA)) - mPairCol = intent.getStringExtra(VerifyConstants.PAIR_COL_EXTRA); - - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); - final SharedPreferences.Editor editor = sharedPref.edit(); - - int scanMode = Integer.valueOf(sharedPref.getString(SettingsActivity.SCAN_MODE_LIST, "-1")); - - if (mPairCol != null) { - editor.putBoolean(SettingsActivity.DISABLE_PAIR, false); - if (scanMode != 4) showPairDialog(); - } else { - editor.putBoolean(SettingsActivity.DISABLE_PAIR, true); - } - - if (mPairCol == null && scanMode == 4) { - editor.putString(SettingsActivity.SCAN_MODE_LIST, "0"); - Toast.makeText(this, - "Switching to default mode, no pair ID found.", - Toast.LENGTH_SHORT).show(); - } - editor.putString(SettingsActivity.FILE_NAME, mFileName); - editor.putString(SettingsActivity.PAIR_NAME, mPairCol); - editor.putString(SettingsActivity.LIST_KEY_NAME, mListId); - editor.apply(); - - clearListView(); - loadSQLToLocal(); - updateCheckedItems(); - break; - } - - if (intent.hasExtra(VerifyConstants.CAMERA_RETURN_ID)) { - ((EditText) findViewById(org.phenoapps.verify.R.id.scannerTextView)) - .setText(intent.getStringExtra(VerifyConstants.CAMERA_RETURN_ID)); - checkScannedItem(); - } - } - } - } - - private void buildListView() { - - ListView idTable = (ListView) findViewById(org.phenoapps.verify.R.id.idTable); - ArrayAdapter idAdapter = - new ArrayAdapter<>(this, org.phenoapps.verify.R.layout.row); - int size = mIds.size(); - for (int i = 0; i < size; i++) { - idAdapter.add(this.mIds.get(this.mIds.keyAt(i))); - } - idTable.setAdapter(idAdapter); - } - - private void clearListView() { - - ListView idTable = (ListView) findViewById(org.phenoapps.verify.R.id.idTable); - final ArrayAdapter adapter = - new ArrayAdapter<>(this, org.phenoapps.verify.R.layout.row); - - idTable.setAdapter(adapter); - adapter.notifyDataSetChanged(); - } - - private void setupDrawer() { - - DrawerLayout dl = (DrawerLayout) findViewById(org.phenoapps.verify.R.id.drawer_layout); - mDrawerToggle = new ActionBarDrawerToggle(this, dl, - org.phenoapps.verify.R.string.drawer_open, org.phenoapps.verify.R.string.drawer_close) { - - public void onDrawerOpened(View drawerView) { - View view = MainActivity.this.getCurrentFocus(); - if (view != null) { - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } - - public void onDrawerClosed(View view) { - } - - }; - - mDrawerToggle.setDrawerIndicatorEnabled(true); - dl.addDrawerListener(mDrawerToggle); - } - - private void setupDrawerContent(NavigationView navigationView) { - navigationView.setNavigationItemSelectedListener( - new NavigationView.OnNavigationItemSelectedListener() { - @Override - public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { - selectDrawerItem(menuItem); - return true; - } - }); - } - - private void selectDrawerItem(MenuItem menuItem) { - int itemId = menuItem.getItemId(); - // constants like id in R class are no longer final, thus can't use switch here - - if (itemId == R.id.nav_import){ - final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); - final int scanMode = Integer.valueOf(sharedPref.getString(SettingsActivity.SCAN_MODE_LIST, "-1")); - final Intent i; - File verifyDirectory = new File(getExternalFilesDir(null), "/Verify"); - - File[] files = verifyDirectory.listFiles(); - - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Select files from?"); - builder.setPositiveButton("Storage", - new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int id) - { - Intent i; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { - i = new Intent(Intent.ACTION_OPEN_DOCUMENT); - }else{ - i = new Intent(Intent.ACTION_GET_CONTENT); - } - i.setType("*/*"); - startActivityForResult(Intent.createChooser(i, "Choose file to import."), VerifyConstants.DEFAULT_CONTENT_REQ); - } - }); - - builder.setNegativeButton("Verify Directory", - new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int id) - { - - AlertDialog.Builder fileBuilder = new AlertDialog.Builder(MainActivity.this); - fileBuilder.setTitle("Select the sample file"); - final int[] checkedItem = {-1}; - String[] listItems = verifyDirectory.list(); - fileBuilder.setSingleChoiceItems(listItems, checkedItem[0],(fileDialog, which) -> { - checkedItem[0] = which; - - Intent i = new Intent(MainActivity.this, LoaderDBActivity.class); - i.setData(Uri.fromFile(files[which])); - startActivityForResult(i, VerifyConstants.LOADER_INTENT_REQ); - fileDialog.dismiss(); - }); - - fileBuilder.show(); - - } - }); - builder.show(); - } else if (itemId == R.id.nav_settings) { - final Intent settingsIntent = new Intent(this, SettingsActivity.class); - startActivityForResult(settingsIntent, VerifyConstants.SETTINGS_INTENT_REQ); - } else if (itemId == R.id.nav_export) { - askUserExportFileName(); - } else if (itemId == R.id.nav_about) { - showAboutDialog(); - } else if (itemId == R.id.nav_intro) { - final Intent intro_intent = new Intent(MainActivity.this, IntroActivity.class); - runOnUiThread(new Runnable() { - @Override public void run() { - startActivity(intro_intent); - } - }); - } - DrawerLayout dl = (DrawerLayout) findViewById(org.phenoapps.verify.R.id.drawer_layout); - dl.closeDrawers(); - } - - private void showPairDialog() { - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Pair column selected, would you like to switch to Pair mode?"); - - builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(SettingsActivity.SCAN_MODE_LIST, "4"); - editor.apply(); - } - }); - - builder.setNegativeButton("No thanks", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - - } - }); - - builder.show(); - } - - private void showAboutDialog() - { - android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this); - { - android.view.View personView = this.getLayoutInflater().inflate( - org.phenoapps.verify.R.layout.about, new android.widget.LinearLayout(this), - false); - - { - assert personView != null; - android.widget.TextView versionTextView = (android.widget.TextView) - personView.findViewById(org.phenoapps.verify.R.id.tvVersion); - try - { - android.content.pm.PackageInfo packageInfo = - this.getPackageManager().getPackageInfo(this.getPackageName(), 0); - assert packageInfo != null; - assert versionTextView != null; - versionTextView.setText(this.getResources().getString( - org.phenoapps.verify.R.string.versiontitle) + - ' ' + packageInfo.versionName); - } - catch (android.content.pm.PackageManager.NameNotFoundException e) - { e.printStackTrace(); } - versionTextView.setOnClickListener(new android.view.View.OnClickListener() - { - @java.lang.Override - public void onClick(android.view.View v) - { MainActivity.this.showChangeLog(); } - }); - } - - builder.setCancelable(true); - builder.setTitle (this.getResources().getString( - org.phenoapps.verify.R.string.about)); - builder.setView(personView); - } - - builder.setNegativeButton( - this.getResources().getString(org.phenoapps.verify.R.string.ok), - new android.content.DialogInterface.OnClickListener() - { - @java.lang.Override - public void onClick(android.content.DialogInterface dialog, int which) - { - assert dialog != null; - dialog.dismiss(); - } - }); - - builder.show(); - } - - private void showChangeLog() { - - } - - @Override - final protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - mDrawerToggle.syncState(); - } - - @Override - final public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mDrawerToggle.onConfigurationChanged(newConfig); - } - - private void launchIntro() { - - new Thread(new Runnable() { - @Override - public void run() { - - // Launch app intro - final Intent i = new Intent(MainActivity.this, IntroActivity.class); - - runOnUiThread(new Runnable() { - @Override public void run() { - startActivity(i); - } - }); - - - } - }).start(); - } - - /* Checks if external storage is available for read and write */ static private boolean isExternalStorageWritable() { return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); } - @Override - final public void onDestroy() { - mDbHelper.close(); - super.onDestroy(); - } @Override public void onRequestPermissionsResult(int resultCode, String[] permissions, int[] granted) { - super.onRequestPermissionsResult(resultCode, permissions, granted); boolean externalWriteAccept = false; if (resultCode == VerifyConstants.PERM_REQ) { @@ -1191,8 +159,27 @@ public void onRequestPermissionsResult(int resultCode, String[] permissions, int } @Override - final public void onPause() { - super.onPause(); + public void onBackPressed() { + NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); + NavDestination currentDestination = navController.getCurrentDestination(); + + if (currentDestination != null && + (currentDestination.getId() == R.id.Settings || currentDestination.getId() == R.id.Compare)) { + // Navigate to the Home fragment + navController.navigate(R.id.Home); + } else if (currentDestination != null && currentDestination.getId() == R.id.Home) { + // Handle the back button for the Home fragment + if (this.lastBackPressTime + BACK_PRESS_INTERVAL > System.currentTimeMillis()) { + super.onBackPressed(); + return; + } else { + Toast.makeText(this, "Press back again to exit", Toast.LENGTH_SHORT).show(); + } + this.lastBackPressTime = System.currentTimeMillis(); + } else { + // Handle other cases or call the super method + super.onBackPressed(); + } } } diff --git a/app/src/main/java/org/phenoapps/verify/SettingsActivity.java b/app/src/main/java/org/phenoapps/verify/SettingsActivity.java deleted file mode 100644 index fb5a18f..0000000 --- a/app/src/main/java/org/phenoapps/verify/SettingsActivity.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.phenoapps.verify; - -import android.os.Bundle; - -import androidx.appcompat.app.AppCompatActivity; -import android.view.MenuItem; - -public class SettingsActivity extends AppCompatActivity { - - public static String FILE_NAME = "org.phenoapps.verify.FILE_NAME"; - public static String SCAN_MODE_LIST = "org.phenoapps.verify.SCAN_MODE"; - public static String AUDIO_ENABLED = "org.phenoapps.verify.AUDIO_ENABLED"; - public static String TUTORIAL_MODE = "org.phenoapps.verify.TUTORIAL_MODE"; - public static String FIRST_NAME = "org.phenoapps.verify.FIRST_NAME"; - public static String LAST_NAME = "org.phenoapps.verify.LAST_NAME"; - public static String LIST_KEY_NAME = "org.phenoapps.verify.LIST_KEY_NAME"; - public static String PAIR_NAME = "org.phenoapps.verify.PAIR_NAME"; - public static String DISABLE_PAIR = "org.phenoapps.verify.DISABLE_PAIR"; - public static String AUX_INFO = "org.phenoapps.verify.AUX_INFO"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if(getSupportActionBar() != null){ - getSupportActionBar().setTitle(null); - getSupportActionBar().getThemedContext(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - } - - getFragmentManager().beginTransaction() - .replace(android.R.id.content, new SettingsFragment()) - .commit(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - switch (item.getItemId()) { - case android.R.id.home: - setResult(RESULT_OK); - finish(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/phenoapps/verify/SettingsFragment.java b/app/src/main/java/org/phenoapps/verify/SettingsFragment.java index 577aa32..26674e3 100644 --- a/app/src/main/java/org/phenoapps/verify/SettingsFragment.java +++ b/app/src/main/java/org/phenoapps/verify/SettingsFragment.java @@ -1,30 +1,94 @@ package org.phenoapps.verify; +import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.os.Build; import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceFragment; import android.widget.Toast; -public class SettingsFragment extends PreferenceFragment { +import androidx.preference.Preference; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceFragmentCompat; + +import java.util.prefs.Preferences; + +public class SettingsFragment extends PreferenceFragmentCompat { + + + public static final CharSequence INTRO_BUTTON = "org.phenoapps.verify.INTRO"; + public static final CharSequence ABOUT_BUTTON = "org.phenoapps.verify.ABOUT"; + public static String FILE_NAME = "org.phenoapps.verify.FILE_NAME"; + public static String SCAN_MODE_LIST = "org.phenoapps.verify.SCAN_MODE"; + public static String AUDIO_ENABLED = "org.phenoapps.verify.AUDIO_ENABLED"; + public static String TUTORIAL_MODE = "org.phenoapps.verify.TUTORIAL_MODE"; + public static String NAME = "org.phenoapps.verify.NAME"; + public static String LIST_KEY_NAME = "org.phenoapps.verify.LIST_KEY_NAME"; + public static String PAIR_NAME = "org.phenoapps.verify.PAIR_NAME"; + public static String DISABLE_PAIR = "org.phenoapps.verify.DISABLE_PAIR"; + public static String AUX_INFO = "org.phenoapps.verify.AUX_INFO"; + + + private void showChangeLog() { + + } + private void showAboutDialog(Context ctx) + { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + Intent i = new Intent(getContext(), AboutActivity.class); + startActivity(i); + } + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - addPreferencesFromResource(org.phenoapps.verify.R.xml.preferences); + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + + setPreferencesFromResource(R.xml.preferences, rootKey); + final SharedPreferences sharedPrefs = super.getPreferenceManager().getSharedPreferences(); - ListPreference mode = (ListPreference) findPreference(SettingsActivity.SCAN_MODE_LIST); + ListPreference mode = findPreference(SCAN_MODE_LIST); + Preference introButton = findPreference(INTRO_BUTTON); + Preference aboutButton = findPreference(ABOUT_BUTTON); + + aboutButton.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + showAboutDialog(getContext()); + } + return true; + } + }); + introButton.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + final Intent intro_intent = new Intent(getContext(), IntroActivity.class); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + startActivity(intro_intent); + } + }); + } + return true; + } + }); mode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { //check if Pair mode is chosen, if it's disabled then show a message and switch //back to default mode. @Override public boolean onPreferenceChange(Preference preference, Object o) { if (o.equals("4") && - sharedPrefs.getBoolean(SettingsActivity.DISABLE_PAIR, false)) { + sharedPrefs.getBoolean(DISABLE_PAIR, false)) { ((ListPreference) preference).setValue("0"); Toast.makeText(getActivity(), "Pair mode cannot be used without setting a pair ID.", diff --git a/app/src/main/java/org/phenoapps/verify/UriHandler.java b/app/src/main/java/org/phenoapps/verify/UriHandler.java index 51c7d5f..851c11c 100644 --- a/app/src/main/java/org/phenoapps/verify/UriHandler.java +++ b/app/src/main/java/org/phenoapps/verify/UriHandler.java @@ -55,7 +55,7 @@ public static String getFileName(@NonNull Context context, Uri uri) { return fileName; } -//test + /** * Returns the effective file name from the provided Uri. * @param fileName diff --git a/app/src/main/java/org/phenoapps/verify/ValueModel.java b/app/src/main/java/org/phenoapps/verify/ValueModel.java new file mode 100644 index 0000000..7945e0d --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/ValueModel.java @@ -0,0 +1,36 @@ +package org.phenoapps.verify; + +public class ValueModel { + private String prefix; + private String value; + private boolean auxValue = false; + + public ValueModel(){ + this.value = ""; + this.prefix = ""; + } + + public String getPrefix() { + return prefix; + } + + public String getValue() { + return value; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public void setValue(String value) { + this.value = value; + } + + public void setAuxValue(boolean auxValue) { + this.auxValue = auxValue; + } + + public boolean getAuxValue(){ + return this.auxValue; + } +} diff --git a/app/src/main/java/org/phenoapps/verify/VerifyConstants.java b/app/src/main/java/org/phenoapps/verify/VerifyConstants.java index cfc395c..5c6861c 100644 --- a/app/src/main/java/org/phenoapps/verify/VerifyConstants.java +++ b/app/src/main/java/org/phenoapps/verify/VerifyConstants.java @@ -2,7 +2,7 @@ import android.Manifest; -class VerifyConstants { +public class VerifyConstants { final static String[] permissions = new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE, @@ -15,7 +15,7 @@ class VerifyConstants { final static int CAMERA_INTENT_REQ = 102; final static int SETTINGS_INTENT_REQ = 103; final static int DEFAULT_CONTENT_REQ = 104; - final static int PICK_CUSTOM_DEST = 105; + public final static int PICK_CUSTOM_DEST = 105; //extras final static String CSV_URI = "org.phenoapps.verify.CSV_URI"; diff --git a/app/src/main/java/org/phenoapps/verify/ViewModel/CompareViewModel.java b/app/src/main/java/org/phenoapps/verify/ViewModel/CompareViewModel.java new file mode 100644 index 0000000..b9ba11c --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/ViewModel/CompareViewModel.java @@ -0,0 +1,24 @@ +package org.phenoapps.verify.ViewModel; +import android.util.Log; + +import androidx.lifecycle.ViewModel; + +public class CompareViewModel extends ViewModel { + // Define your data here + private Mode mMode = Mode.Matches; + + public Mode getMode() { + return mMode; + } + + public void setMode(Mode mode) { + Log.d("CompareViewModel", "Setting mode to: $mode"); + this.mMode = mode; + } + + // Enum for Mode + public enum Mode { + Contains, + Matches + } +} \ No newline at end of file diff --git a/app/src/main/java/org/phenoapps/verify/ViewModel/HomeViewModel.java b/app/src/main/java/org/phenoapps/verify/ViewModel/HomeViewModel.java new file mode 100644 index 0000000..3eb49f0 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/ViewModel/HomeViewModel.java @@ -0,0 +1,172 @@ +package org.phenoapps.verify.ViewModel; + +import android.app.Activity; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteStatement; +import android.preference.PreferenceManager; +import android.text.InputType; +import android.util.SparseArray; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.ViewModel; + +import org.phenoapps.verify.HomeFragment; +import org.phenoapps.verify.IdEntryContract; +import org.phenoapps.verify.IdEntryDbHelper; +import org.phenoapps.verify.R; +import org.phenoapps.verify.SettingsFragment; +import org.phenoapps.verify.ValueModel; +import org.phenoapps.verify.utilities.IdEntryRepository; + +import java.util.ArrayList; +import java.util.HashSet; + +public class HomeViewModel extends ViewModel { +// private final IdEntryDbHelper mDbHelper; + + private final IdEntryRepository dbRepo; + private String mListId; + +// private final Activity activity; + + private SparseArray mIds; + + private String mPairCol; + + private String mNextPairVal; + + + + + public HomeViewModel(Activity activity){ + dbRepo = new IdEntryRepository(activity); + this.mNextPairVal = null; + } + + public String getmNextPairVal() { + return mNextPairVal; + } + + public IdEntryDbHelper getmDbHelper() { + return dbRepo.getmDbHelper(); + } + + public void setmListId(String mListId) { + this.mListId = mListId; + } + + public SparseArray getmIds() { + return mIds; + } + + public String getmPairCol() { + return mPairCol; + } + + public void setmPairCol(String mPairCol) { + this.mPairCol = mPairCol; + } + + public void setmIds(SparseArray mIds) { + this.mIds = mIds; + } + + public void setmNextPairVal(String mNextPairVal) { + this.mNextPairVal = mNextPairVal; + } + + public SQLiteStatement getSqlUpdateUserAndDate() { + return dbRepo.getSqlUpdateUserAndDate(); + } + + public synchronized HashSet updateCheckedItems() { + + + //list of ideas to populate and update the view with + final HashSet ids = new HashSet<>(); + + final String table = IdEntryContract.IdEntry.TABLE_NAME; + final String[] columns = new String[] { mListId }; + final String selection = "color = 1"; + dbRepo.helperUpdateItems(table, columns, selection, mListId); + return ids; + } + + public synchronized void loadSQLToLocal(Activity activity) { + + mIds = new SparseArray<>(); + + + final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(activity); + mListId = sharedPref.getString(SettingsFragment.LIST_KEY_NAME, null); + mPairCol = sharedPref.getString(SettingsFragment.PAIR_NAME, null); + + if (mListId != null) { + prepareStatements(); + loadBarcodes(); + } + } + + public ArrayList getData(String scannedId) { + + String table = IdEntryContract.IdEntry.TABLE_NAME; + String[] selectionArgs = new String[]{scannedId}; + + return dbRepo.fetchEntries(table, mListId, selectionArgs); + } + + private void loadBarcodes() { + this.mIds = dbRepo.loadBarcodes(mListId); + } + + public void executeScan(String id){ + String table = IdEntryContract.IdEntry.TABLE_NAME; + String[] columnsNames = new String[] { mPairCol }; + String selection = mListId + "=?"; + String[] selectionArgs = { id }; + mNextPairVal = dbRepo.scanDb(table, columnsNames, selection, selectionArgs, mPairCol); + + } + + public String getmListId() { + return mListId; + } + + public void executeDelete(String id){ + dbRepo.delete(id); + + } + + public void executeUserUpdate(String name, String date, String id){ + dbRepo.executeUserUpdate(name, date, id); + } + + public void executeUpdate(String id){ + dbRepo.executeUpdate(id); + } + + public Boolean checkIdExists(String id) { + + final String table = IdEntryContract.IdEntry.TABLE_NAME; + final String[] selectionArgs = new String[] { id }; + + return dbRepo.checkExists(table, mListId, selectionArgs); + } + + public void updateDb(String value, String id){ + + dbRepo.updateDb(value, id); + } + + public void prepareStatements() { + dbRepo.prepareStatements(mListId); + } +} diff --git a/app/src/main/java/org/phenoapps/verify/utilities/FileExport.java b/app/src/main/java/org/phenoapps/verify/utilities/FileExport.java new file mode 100644 index 0000000..31b68fc --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/utilities/FileExport.java @@ -0,0 +1,222 @@ +package org.phenoapps.verify.utilities; + +import static androidx.core.app.ActivityCompat.startActivityForResult; + +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.media.MediaScannerConnection; +import android.net.Uri; +import android.os.Environment; +import android.text.InputType; +import android.widget.EditText; +import android.widget.Toast; +import android.util.Log; + + +import androidx.appcompat.app.AlertDialog; + +import org.phenoapps.verify.IdEntryContract; +import org.phenoapps.verify.IdEntryDbHelper; +import org.phenoapps.verify.VerifyConstants; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +public class FileExport { + + private final Activity activity; + final static private String line_separator = System.getProperty("line.separator"); + private String fileName; + + final private IdEntryDbHelper dbHelper; + public FileExport(Activity activity, String fileName, IdEntryDbHelper dbHelper){ + this.fileName = fileName; + this.dbHelper = dbHelper; + this.activity = activity; + } + + + public synchronized void askUserExportFileName(IntentHelper helper) { + + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle("Choose name for exported file."); + final EditText input = new EditText(activity); + + final Calendar c = Calendar.getInstance(); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + + int lastDot = fileName.lastIndexOf('.'); + if (lastDot != -1) { + fileName = fileName.substring(0, lastDot); + } + input.setText("Verify_"+ sdf.format(c.getTime())); + input.setInputType(InputType.TYPE_CLASS_TEXT); + builder.setView(input); + + builder.setPositiveButton("Export", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int which) { + String value = input.getText().toString(); + fileName = value; + final Intent i; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + i = new Intent(Intent.ACTION_CREATE_DOCUMENT); + i.setType("*/*"); + i.putExtra(Intent.EXTRA_TITLE, value+".csv"); + helper.startIntent(i); + }else{ + writeToExportPath(); + } + } + }); + builder.show(); + } + + public void writeToExportPath() { + String value = fileName; + + if (!value.isEmpty()) { + if (isExternalStorageWritable()) { + try { + File verifyDirectory = new File(Environment.getExternalStorageDirectory().getPath() + "/Verify"); + final File output = new File(verifyDirectory, value + ".csv"); + final FileOutputStream fstream = new FileOutputStream(output); + final SQLiteDatabase db = dbHelper.getReadableDatabase(); + final String table = IdEntryContract.IdEntry.TABLE_NAME; + final Cursor cursor = db.query(table, null, null, null, null, null, null); + + if(cursor.getCount() == 0) { + Log.e("FileExport", "No data to export"); + Toast.makeText(activity, "No data available for export", Toast.LENGTH_SHORT).show(); + return; + } + + // first write header line + final String[] headers = cursor.getColumnNames(); + for (int i = 0; i < headers.length; i++) { + if (i != 0) fstream.write(",".getBytes()); + fstream.write(headers[i].getBytes()); + } + fstream.write(line_separator.getBytes()); + + // populate text file with current database values + while (cursor.moveToNext()) { + for (int i = 0; i < headers.length; i++) { + if (i != 0) fstream.write(",".getBytes()); + final String val = cursor.getString( + cursor.getColumnIndexOrThrow(headers[i]) + ); + if (val == null) fstream.write("null".getBytes()); + else fstream.write(val.getBytes()); + } + fstream.write(line_separator.getBytes()); + } + + cursor.close(); + fstream.flush(); + fstream.close(); + scanFile(activity, output); + } catch (SQLiteException e) { + e.printStackTrace(); + Toast.makeText(activity, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + Toast.makeText(activity, "Error creating file", Toast.LENGTH_SHORT).show(); + } catch (IOException io) { + io.printStackTrace(); + Toast.makeText(activity, "Error writing to file", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(activity, "External storage not writable.", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(activity, "Must enter a file name.", Toast.LENGTH_SHORT).show(); + } + } + + + public static void scanFile(Context ctx, File filePath) { + MediaScannerConnection.scanFile(ctx, new String[] { filePath.getAbsolutePath()}, null, null); + } + + public void writeToExportPath(Uri uri) { + String value = fileName; + + if (uri == null) { + Toast.makeText(activity, "Unable to open the specified file", Toast.LENGTH_LONG).show(); + return; + } + + if (!value.isEmpty()) { + if (isExternalStorageWritable()) { + try { + final OutputStream fstream = activity.getContentResolver().openOutputStream(uri); + final SQLiteDatabase db = dbHelper.getReadableDatabase(); + final String table = IdEntryContract.IdEntry.TABLE_NAME; + final Cursor cursor = db.query(table, null, null, null, null, null, null); + + if(cursor.getCount() == 0) { + Log.e("FileExport", "No data to export"); + Toast.makeText(activity, "No data available for export", Toast.LENGTH_SHORT).show(); + return; + } + + // first write header line + final String[] headers = cursor.getColumnNames(); + for (int i = 0; i < headers.length; i++) { + if (i != 0) fstream.write(",".getBytes()); + fstream.write(headers[i].getBytes()); + } + fstream.write(line_separator.getBytes()); + + // populate text file with current database values + while (cursor.moveToNext()) { + for (int i = 0; i < headers.length; i++) { + if (i != 0) fstream.write(",".getBytes()); + final String val = cursor.getString( + cursor.getColumnIndexOrThrow(headers[i]) + ); + if (val == null) fstream.write("null".getBytes()); + else fstream.write(val.getBytes()); + } + fstream.write(line_separator.getBytes()); + } + + cursor.close(); + fstream.flush(); + fstream.close(); + scanFile(activity, new File(uri.getPath())); + } catch (SQLiteException e) { + e.printStackTrace(); + Toast.makeText(activity, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + Toast.makeText(activity, "Error creating file", Toast.LENGTH_SHORT).show(); + } catch (IOException io) { + io.printStackTrace(); + Toast.makeText(activity, "Error writing to file", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(activity, "External storage not writable.", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(activity, "Must enter a file name.", Toast.LENGTH_SHORT).show(); + } + } + + + static private boolean isExternalStorageWritable() { + return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); + } +} diff --git a/app/src/main/java/org/phenoapps/verify/utilities/IdEntryRepository.java b/app/src/main/java/org/phenoapps/verify/utilities/IdEntryRepository.java new file mode 100644 index 0000000..1001421 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/utilities/IdEntryRepository.java @@ -0,0 +1,209 @@ +package org.phenoapps.verify.utilities; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteStatement; +import android.util.SparseArray; + + +import org.apache.poi.ss.formula.functions.Value; +import org.phenoapps.verify.HomeFragment; +import org.phenoapps.verify.IdEntryContract; +import org.phenoapps.verify.IdEntryDbHelper; +import org.phenoapps.verify.ValueModel; + +import java.util.ArrayList; +import java.util.HashSet; + +public class IdEntryRepository { + private final IdEntryDbHelper dbHelper; + private SQLiteStatement sqlDeleteId; + private SQLiteStatement sqlUpdateChecked; + private SQLiteStatement sqlUpdateUserAndDate; + private SQLiteStatement sqlUpdateNote; + + + public IdEntryRepository(Context context) { + dbHelper = new IdEntryDbHelper(context); + } + public void delete(String id) { + if (sqlDeleteId == null){ + return; + } + sqlDeleteId.bindAllArgsAsStrings(new String[]{id}); + sqlDeleteId.executeUpdateDelete(); + + } + public HashSet helperUpdateItems(String table, String[] columns, String selection, String listId) { + final SQLiteDatabase db = dbHelper.getReadableDatabase(); + final HashSet ids = new HashSet<>(); + try { + final Cursor cursor = db.query(table, columns, selection, null, null, null, null); + if (cursor.moveToFirst()) { + do { + String id = cursor.getString( + cursor.getColumnIndexOrThrow(listId) + ); + + ids.add(id); + } while (cursor.moveToNext()); + } + cursor.close(); + } catch (SQLiteException e) { + e.printStackTrace(); + } + return ids; + } + + public ArrayList fetchEntries(String table, String listId, String[] selectionArgs) { + SQLiteDatabase db = dbHelper.getReadableDatabase(); + Cursor cursor = db.query(table, null, listId + "=?", selectionArgs, null, null, null); + String[] headerTokens = cursor.getColumnNames(); + ArrayList values = new ArrayList(); + + if (cursor.moveToFirst()) { + for( String header:headerTokens) { + if (!header.equals(listId)) { + + final String val = cursor.getString( + cursor.getColumnIndexOrThrow(header) + ); + + if (header.equals("color") || header.equals("scan_count") || header.equals("date") + || header.equals("user") || header.equals("note")) { + ValueModel auxModel = new ValueModel(); + if (header.equals("color")) continue; + else if (header.equals("scan_count")) auxModel.setPrefix("Number of scans"); + else if (header.equals("date")) auxModel.setPrefix("Date"); + else auxModel.setPrefix(header); + if (val != null) auxModel.setValue(val); + auxModel.setAuxValue(true); + values.add(auxModel); + } else { + ValueModel model = new ValueModel(); + model.setPrefix(header); + if(val != null){ + model.setValue(val); + } + values.add(model); + } + } + } + } + cursor.close(); + return values; + } + + public String scanDb(String table, String[] columnsNames, String selection, String[] selectionArgs, String mPairCol) { + SQLiteDatabase db = dbHelper.getWritableDatabase(); + Cursor cursor = db.query(table, columnsNames, selection, selectionArgs, null, null, null); + if(cursor.moveToFirst()) { + String value = cursor.getString( + cursor.getColumnIndexOrThrow(mPairCol)); + cursor.close(); + return value; + } + return null; + } + + public void executeUserUpdate(String name, String date, String id) { + if (sqlUpdateUserAndDate == null){ + return; + } + sqlUpdateUserAndDate.bindAllArgsAsStrings(new String[]{ + name, + date, + id + }); + sqlUpdateUserAndDate.executeUpdateDelete(); + } + + public void executeUpdate(String id) { + if (sqlUpdateChecked == null){ + return; + } + sqlUpdateChecked.bindAllArgsAsStrings(new String[]{id}); + sqlUpdateChecked.executeUpdateDelete(); + } + + public Boolean checkExists(String table, String mListId, String[] selectionArgs) { + SQLiteDatabase db = dbHelper.getReadableDatabase(); + final Cursor cursor = db.query(table, null, mListId + "=?", selectionArgs, null, null, null); + if (cursor.moveToFirst()) { + cursor.close(); + return true; + } else { + cursor.close(); + return false; + } + } + public void updateDb(String value, String id) { + if (sqlUpdateNote != null) { + sqlUpdateNote.bindAllArgsAsStrings(new String[]{ + value, id + }); + sqlUpdateNote.executeUpdateDelete(); + } + } + + public void prepareStatements(String mListId) { + final SQLiteDatabase db = dbHelper.getWritableDatabase(); + try { + String updateNoteQuery = "UPDATE VERIFY SET note = ? WHERE " + mListId + " = ?"; + sqlUpdateNote = db.compileStatement(updateNoteQuery); + + String deleteIdQuery = "DELETE FROM VERIFY WHERE " + mListId + " = ?"; + sqlDeleteId = db.compileStatement(deleteIdQuery); + + String updateCheckedQuery = "UPDATE VERIFY SET color = 1 WHERE " + mListId + " = ?"; + sqlUpdateChecked = db.compileStatement(updateCheckedQuery); + + String updateUserAndDateQuery = + "UPDATE VERIFY SET user = ?, date = ?, scan_count = scan_count + 1 WHERE " + mListId + " = ?"; + sqlUpdateUserAndDate = db.compileStatement(updateUserAndDateQuery); + } catch(SQLiteException e) { + e.printStackTrace(); + } + } + + public SparseArray loadBarcodes(String mListId) { + SQLiteDatabase db = dbHelper.getReadableDatabase(); + SparseArray mIds = new SparseArray<>(); + try { + final String table = IdEntryContract.IdEntry.TABLE_NAME; + final Cursor cursor = db.query(table, null, null, null, null, null, null); + + if (cursor.moveToFirst()) { + do { + final String[] headers = cursor.getColumnNames(); + for (String header : headers) { + + final String val = cursor.getString( + cursor.getColumnIndexOrThrow(header) + ); + + if (header.equals(mListId)) { + mIds.append(mIds.size(), val); + } + } + } while (cursor.moveToNext()); + } + cursor.close(); + + } catch (SQLiteException e) { + e.printStackTrace(); + } + return mIds; + } + + public SQLiteStatement getSqlUpdateUserAndDate() { + return sqlUpdateUserAndDate; + } + + public IdEntryDbHelper getmDbHelper() { + return dbHelper; + } + +} diff --git a/app/src/main/java/org/phenoapps/verify/utilities/IntentHelper.java b/app/src/main/java/org/phenoapps/verify/utilities/IntentHelper.java new file mode 100644 index 0000000..c12fe67 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/utilities/IntentHelper.java @@ -0,0 +1,7 @@ +package org.phenoapps.verify.utilities; + +import android.content.Intent; + +public interface IntentHelper { + void startIntent(Intent i); +} diff --git a/app/src/main/java/org/phenoapps/verify/utilities/RingUtility.java b/app/src/main/java/org/phenoapps/verify/utilities/RingUtility.java new file mode 100644 index 0000000..59f1d24 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/utilities/RingUtility.java @@ -0,0 +1,20 @@ +package org.phenoapps.verify.utilities; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.media.MediaPlayer; +import android.preference.PreferenceManager; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import org.phenoapps.verify.SettingsFragment; + +public interface RingUtility { + + public void ringNotification(boolean success); + + + +} diff --git a/app/src/main/res/drawable-anydpi/ic_home.xml b/app/src/main/res/drawable-anydpi/ic_home.xml new file mode 100644 index 0000000..3eb8fe0 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_home.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_export.png b/app/src/main/res/drawable-hdpi/ic_export.png index 19db11c..f36eacd 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_export.png and b/app/src/main/res/drawable-hdpi/ic_export.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_home.png b/app/src/main/res/drawable-hdpi/ic_home.png new file mode 100644 index 0000000..bfbbd81 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_import_white.png b/app/src/main/res/drawable-hdpi/ic_import_white.png new file mode 100644 index 0000000..f90b07a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_import_white.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_settings.png b/app/src/main/res/drawable-hdpi/ic_settings.png index 4cb8e41..bda5e85 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_settings.png and b/app/src/main/res/drawable-hdpi/ic_settings.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_export.png b/app/src/main/res/drawable-mdpi/ic_export.png index da28c68..2525d1c 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_export.png and b/app/src/main/res/drawable-mdpi/ic_export.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_home.png b/app/src/main/res/drawable-mdpi/ic_home.png new file mode 100644 index 0000000..5c6b248 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_import_white.png b/app/src/main/res/drawable-mdpi/ic_import_white.png new file mode 100644 index 0000000..f90b07a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_import_white.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_settings.png b/app/src/main/res/drawable-mdpi/ic_settings.png index cf6c63e..bda5e85 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_settings.png and b/app/src/main/res/drawable-mdpi/ic_settings.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_export.png b/app/src/main/res/drawable-xhdpi/ic_export.png index be8ce99..10d6d37 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_export.png and b/app/src/main/res/drawable-xhdpi/ic_export.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_home.png b/app/src/main/res/drawable-xhdpi/ic_home.png new file mode 100644 index 0000000..00ba157 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_import_white.png b/app/src/main/res/drawable-xhdpi/ic_import_white.png new file mode 100644 index 0000000..f90b07a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_import_white.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_settings.png b/app/src/main/res/drawable-xhdpi/ic_settings.png index 3170916..bda5e85 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_settings.png and b/app/src/main/res/drawable-xhdpi/ic_settings.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_export.png b/app/src/main/res/drawable-xxhdpi/ic_export.png index f0efa37..92ee9ec 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_export.png and b/app/src/main/res/drawable-xxhdpi/ic_export.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_home.png b/app/src/main/res/drawable-xxhdpi/ic_home.png new file mode 100644 index 0000000..35d7634 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_import_white.png b/app/src/main/res/drawable-xxhdpi/ic_import_white.png new file mode 100644 index 0000000..f90b07a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_import_white.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_settings.png b/app/src/main/res/drawable-xxhdpi/ic_settings.png index 55d0279..bda5e85 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_settings.png and b/app/src/main/res/drawable-xxhdpi/ic_settings.png differ diff --git a/app/src/main/res/drawable/bottom_nav_color.xml b/app/src/main/res/drawable/bottom_nav_color.xml new file mode 100644 index 0000000..c6fc209 --- /dev/null +++ b/app/src/main/res/drawable/bottom_nav_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_person_profile.xml b/app/src/main/res/drawable/ic_person_profile.xml new file mode 100644 index 0000000..d21debf --- /dev/null +++ b/app/src/main/res/drawable/ic_person_profile.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml index 08a56bf..88ac3ed 100644 --- a/app/src/main/res/layout-land/activity_main.xml +++ b/app/src/main/res/layout-land/activity_main.xml @@ -1,108 +1,25 @@ - - - - - - - - -