diff --git a/app/build.gradle b/app/build.gradle index 4a5447f..b62b6e6 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,23 @@ 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' } repositories { mavenCentral() + maven { url 'https://jitpack.io' } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b290ec8..444bbcc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,31 +12,38 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + + android:exported="true" + android:windowSoftInputMode="adjustPan"> + - - - - - - - - - + android:name=".CompareActivity" + 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 index 1a066d8..845b420 100644 --- a/app/src/main/java/org/phenoapps/verify/CompareActivity.kt +++ b/app/src/main/java/org/phenoapps/verify/CompareActivity.kt @@ -164,7 +164,6 @@ class CompareActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(org.phenoapps.verify.R.layout.activity_compare) - } 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..868fcb0 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/CompareFragment.kt @@ -0,0 +1,204 @@ +package org.phenoapps.verify; + +import android.annotation.SuppressLint; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; + +import android.app.Activity; +import android.content.Context +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.EditText +import android.widget.ImageView +import android.widget.RadioButton +import android.widget.RadioGroup +import androidx.appcompat.app.AlertDialog +import com.google.zxing.ResultPoint +import com.journeyapps.barcodescanner.BarcodeCallback +import com.journeyapps.barcodescanner.BarcodeResult +import com.journeyapps.barcodescanner.DecoratedBarcodeView + +import org.phenoapps.verify.databinding.FragmentCompareBinding; + +/** + * An example full-screen activity that shows and hides the system UI (i.e. + * status bar and navigation/system bar) with user interaction. + */ + +public class CompareFragment : Fragment() { + + enum class Mode { + Contains, + Matches + } + + private lateinit var view: View; + + 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 + + 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(result.text ?: "") + + mFocused = when (mFocused) { + R.id.editText -> R.id.editText2 + else -> R.id.editText + } + + view.findViewById(mFocused).requestFocus() + } + barcodeScannerView.resume() + } + override fun possibleResultPoints(resultPoints: MutableList?) { + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + var layoutView = inflater.inflate(R.layout.activity_compare, container, false); + return layoutView; + } + + + override fun onStart() { + super.onStart() + val choiceView = layoutInflater.inflate(R.layout.choice_compare_layout, null) + + val radioGroup = choiceView.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(context as Context).apply { + + setView(choiceView) + + setTitle("Choose compare mode:") + + setPositiveButton("OK") { _, _ -> + when (radioGroup.checkedRadioButtonId) { + containsRadioButton.id -> mMode = CompareFragment.Mode.Contains + matchesRadioButton.id -> mMode = CompareFragment.Mode.Matches + } + } + } + + builder.show() + + imageView = view.findViewById(R.id.imageView) + firstEditText = view.findViewById(R.id.editText) + secondEditText = view.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) { + CompareFragment.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) + } + } + CompareFragment.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 = view.findViewById(R.id.zxing_barcode_scanner) + barcodeScannerView.barcodeView.cameraSettings.isContinuousFocusEnabled = true + barcodeScannerView.barcodeView.cameraSettings.isBarcodeSceneModeEnabled = true + barcodeScannerView.decodeContinuous(callback) + + val actionBar = (activity as AppCompatActivity).supportActionBar; + if (actionBar != null) { + actionBar.title = "Compare Barcodes" + actionBar.themedContext + } + + imageView.setOnClickListener { + firstEditText.setText("") + secondEditText.setText("") + firstEditText.requestFocus() + imageView.visibility = View.INVISIBLE + } + } + + override fun onResume() { + super.onResume() + + barcodeScannerView.resume() + } + + override fun onPause() { + super.onPause() + + barcodeScannerView.pause() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + this.view = view; + } +} \ 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..4371319 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/CustomAdapter.java @@ -0,0 +1,56 @@ +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; + + 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 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) { + holder.getTextView().setText(values.get(position)); + } + + @Override + public int getItemCount() { + return values.size(); + } +} \ No newline at end of file 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..7653e25 --- /dev/null +++ b/app/src/main/java/org/phenoapps/verify/HomeFragment.java @@ -0,0 +1,1039 @@ +package org.phenoapps.verify; + +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.media.MediaScannerConnection; +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.ActionMenuView; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.os.Environment; +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 java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashSet; +import java.util.Locale; + +public class HomeFragment extends Fragment { + + + 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; + + //global variable to track matching order + private int mMatchingOrder; + + private String mListId; + private RecyclerView valueView; + private CustomAdapter adapter; + + //pair mode vars + private String mPairCol; + private String mNextPairVal; + + private String mFileName = ""; + + private Toolbar navigationToolBar; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mIds = new SparseArray<>(); + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + + final View auxInfo = getView().findViewById(R.id.auxScrollView); + final View auxValue = getView().findViewById(R.id.auxValueView); + + if (sharedPref.getBoolean(SettingsFragment.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(SettingsFragment.AUX_INFO, false)) { + auxInfo.setVisibility(View.VISIBLE); + auxValue.setVisibility(View.VISIBLE); + } else { + auxInfo.setVisibility(View.GONE); + auxValue.setVisibility(View.GONE); + } + } + }; + + 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(getActivity(), VerifyConstants.permissions, VerifyConstants.PERM_REQ); + + mNextPairVal = null; + mMatchingOrder = 0; + mPairCol = null; + + initializeUIVariables(); + + mDbHelper = new IdEntryDbHelper(getContext()); + + loadSQLToLocal(); + + if (mListId != null) + updateCheckedItems(); + + } + + @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); + } + + + + + 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(); + } + } + + @Nullable + private ActionBar getSupportActionBar() { + ActionBar actionBar = null; + if (getActivity() 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) getView().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) getView().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; + } + }); + + valueView = (RecyclerView) getView().findViewById(R.id.valueView); + valueView.setLayoutManager(new LinearLayoutManager(getContext())); + adapter = new CustomAdapter(new ArrayList()); + valueView.setAdapter(adapter); +// valueView.setLayoutManager(new ); +// valueView.setMovementMethod(new ScrollingMovementMethod()); + + getView().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(getContext()); + int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + boolean displayAux = sharedPref.getBoolean(SettingsFragment.AUX_INFO, true); + + String scannedId = ((EditText) getView().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(); + ArrayList values = new ArrayList(); + 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 { + String value = header + " :\n\t\t"; + if (val != null) value += val; + values.add(value); + } + } + } + cursor.close(); + + adapter.values = values; + adapter.notifyDataSetChanged(); + ((TextView) getView().findViewById(R.id.auxValueView)).setText(auxValues.toString()); + ((EditText) getView().findViewById(R.id.scannerTextView)).setText(""); + ringNotification(true); + } 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(getContext()); + builder.setTitle("Enter a note for the given item."); + final EditText input = new EditText(getContext()); + 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(getContext()); + int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.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(getContext(), "Order matches id: " + id + " at index: " + tableIndex, Toast.LENGTH_SHORT).show(); + ringNotification(true); + } else { + Toast.makeText(getContext(), "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(getContext(), "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 name = sharedPref.getString(SettingsFragment.NAME, ""); + sqlUpdateUserAndDate.bindAllArgsAsStrings(new String[]{ + name, + 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) getView().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(getContext()); + + final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + mListId = sharedPref.getString(SettingsFragment.LIST_KEY_NAME, null); + mPairCol = sharedPref.getString(SettingsFragment.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(getContext()); + builder.setTitle("Choose name for exported file."); + final EditText input = new EditText(getContext()); + + 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(getContext(), output); + /*MediaScannerConnection.scanFile(getContext(), 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(getContext(), "Error in opening the Specified file", Toast.LENGTH_LONG).show(); + } + catch (SQLiteException e) { + e.printStackTrace(); + Toast.makeText(getContext(), "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException io) { + io.printStackTrace(); + } + } else { + Toast.makeText(getContext(), + "External storage not writable.", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(getContext(), + "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 = mFileName; + + if (uri == null){ + Toast.makeText(getContext(), "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 = getContext().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(getContext(), output); + /*MediaScannerConnection.scanFile(getContext(), 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(getContext(), "Error in opening the Specified file", Toast.LENGTH_LONG).show(); + } + catch (SQLiteException e) { + e.printStackTrace(); + Toast.makeText(getContext(), "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException io) { + io.printStackTrace(); + } + } else { + Toast.makeText(getContext(), + "External storage not writable.", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(getContext(), + "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) getView().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) getView().findViewById(org.phenoapps.verify.R.id.idTable); + //update id table array adapter + final ArrayAdapter updatedAdapter = new ArrayAdapter<>(getContext(), 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(getContext()); + final boolean audioEnabled = sharedPref.getBoolean(SettingsFragment.AUDIO_ENABLED, true); + + Log.d("audio", "ringNotification: "+audioEnabled); + + if(success) { //ID found + if(audioEnabled) { + if (success) { + try { + int resID = getResources().getIdentifier("plonk", "raw", getActivity().getPackageName()); + MediaPlayer chimePlayer = MediaPlayer.create(getContext(), resID); + chimePlayer.start(); + + chimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + public void onCompletion(MediaPlayer mp) { + mp.release(); + } + }); + } catch (Exception ignore) { + } + } + } + } + + if(!success) { //ID not found + ((TextView) getView().findViewById(org.phenoapps.verify.R.id.valueView)).setText(""); + + if (audioEnabled) { + if(!success) { + try { + int resID = getResources().getIdentifier("error", "raw", getActivity().getPackageName()); + MediaPlayer chimePlayer = MediaPlayer.create(getContext(), resID); + chimePlayer.start(); + + chimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + public void onCompletion(MediaPlayer mp) { + mp.release(); + } + }); + } catch (Exception ignore) { + } + } + } else { + if (!success) { + Toast.makeText(getContext(), "Scanned ID not found", Toast.LENGTH_SHORT).show(); + } + } + } + } + + @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; + + if (item.getItemId() == actionImport){ + final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + final int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + final Intent i; + File verifyDirectory = new File(getContext().getExternalFilesDir(null), "/Verify"); + + File[] files = verifyDirectory.listFiles(); + + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + 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(getContext()); + 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(getContext(), 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(getContext(), ScanActivity.class); + startActivityForResult(cameraIntent, VerifyConstants.CAMERA_INTENT_REQ); + } + 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 == getActivity().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(getContext(), 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(getContext()); + final SharedPreferences.Editor editor = sharedPref.edit(); + + int scanMode = Integer.valueOf(sharedPref.getString(SettingsFragment.SCAN_MODE_LIST, "-1")); + + 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(getContext(), + "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, mListId); + editor.apply(); + + clearListView(); + loadSQLToLocal(); + updateCheckedItems(); + break; + } + + if (intent.hasExtra(VerifyConstants.CAMERA_RETURN_ID)) { + ((EditText) getView().findViewById(org.phenoapps.verify.R.id.scannerTextView)) + .setText(intent.getStringExtra(VerifyConstants.CAMERA_RETURN_ID)); + checkScannedItem(); + } + } + } + } + + private void buildListView() { + + ListView idTable = (ListView) getView().findViewById(org.phenoapps.verify.R.id.idTable); + ArrayAdapter idAdapter = + new ArrayAdapter<>(getContext(), 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) getView().findViewById(org.phenoapps.verify.R.id.idTable); + final ArrayAdapter adapter = + new ArrayAdapter<>(getContext(), org.phenoapps.verify.R.layout.row); + + idTable.setAdapter(adapter); + adapter.notifyDataSetChanged(); + } + + private void showPairDialog() { + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + 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(getContext()); + 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(getContext(), IntroActivity.class); + + getActivity().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(); + } + +} \ No newline at end of file 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..22d9e32 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,33 @@ 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 = ""; - @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); + setContentView(R.layout.activity_main); - 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); - - 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 +126,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) { @@ -1189,10 +154,4 @@ public void onRequestPermissionsResult(int resultCode, String[] permissions, int copyRawToVerify(verifyDirectory, "verify_pair_sample.csv", R.raw.verify_pair_sample); } } - - @Override - final public void onPause() { - super.onPause(); - } - } 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/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_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_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_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_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 @@ - - - - - - - - -