From 11be8a7c857502c990a87fc3bb43bda828cd3d03 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Wed, 7 Feb 2018 20:48:39 +0100 Subject: [PATCH 1/8] Postpone creating text until view is requested Wait until the measurement is actually to be shown in the gui until creating the spanned text. Cache it so that it doesn't have to be recalculated. Drop the first hidden column that contained the id. Instead implement Adapter.getItemId and use the supplied id in onClickListenerRow. Speeds up the initial loading of the table. --- .../gui/fragments/TableFragment.java | 179 +++++++++--------- 1 file changed, 88 insertions(+), 91 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index 0fdd1ab1..8695693f 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -31,7 +31,6 @@ import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.SpannedString; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; @@ -109,6 +108,9 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { tableDataView = (ListView) tableView.findViewById(R.id.tableDataView); tableHeaderView = (LinearLayout) tableView.findViewById(R.id.tableHeaderView); + tableDataView.setAdapter(new ListViewAdapter()); + tableDataView.setOnItemClickListener(new onClickListenerRow()); + optionMenu = (ImageView) tableView.findViewById(R.id.optionMenu); measurementsList = new ArrayList<>(); @@ -192,15 +194,12 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { @Override public void updateOnView(List scaleMeasurementList) { - tableDataView.setAdapter(new ListViewAdapter(new ArrayList>())); // delete all data in the table with an empty adapter array list - - if (scaleMeasurementList.isEmpty()) { - return; - } - final int maxSize = 25; - int subpageCount = (int)Math.ceil(scaleMeasurementList.size() / (double)maxSize); + final int subpageCount = (int)Math.ceil(scaleMeasurementList.size() / (double)maxSize); + if (selectedSubpageNr >= subpageCount) { + selectedSubpageNr = Math.max(0, subpageCount - 1); + } subpageView.removeAllViews(); @@ -216,7 +215,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { moveSubpageLeft.setEnabled(selectedSubpageNr > 0); subpageView.addView(moveSubpageLeft); - for (int i=0; i 1) { TextView selectedSubpageNrView = (TextView) subpageView.getChildAt(selectedSubpageNr + 1); if (selectedSubpageNrView != null) { @@ -247,6 +247,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { tableHeaderView.removeAllViews(); + ArrayList visibleMeasurements = new ArrayList<>(); for (MeasurementView measurement : measurementsList) { measurement.updatePreferences(prefs); @@ -259,50 +260,16 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { headerIcon.getLayoutParams().height = pxImageDp(20); tableHeaderView.addView(headerIcon); + + visibleMeasurements.add(measurement); } } - ArrayList> dataRowList = new ArrayList<>(); + ListViewAdapter adapter = (ListViewAdapter) tableDataView.getAdapter(); - int displayCount = 0; - - for (int i = (maxSize * selectedSubpageNr); i < scaleMeasurementList.size(); i++) { - ScaleMeasurement scaleMeasurement = scaleMeasurementList.get(i); - - ScaleMeasurement prevScaleMeasurement = null; - if (i < scaleMeasurementList.size() - 1) { - prevScaleMeasurement = scaleMeasurementList.get(i + 1); - } - - HashMap dataRow = new HashMap<>(); - - int columnNr = 0; - dataRow.put(columnNr++, new SpannedString(Long.toString(scaleMeasurement.getId()))); - - for (MeasurementView measurement : measurementsList) { - measurement.loadFrom(scaleMeasurement, prevScaleMeasurement); - - if (measurement.isVisible()) { - SpannableStringBuilder text = new SpannableStringBuilder(); - text.append(measurement.getValueAsString()); - text.append("\n"); - measurement.appendDiffValue(text); - - dataRow.put(columnNr++, text); - } - } - - dataRowList.add(dataRow); - - displayCount++; - - if (maxSize <= displayCount) { - break; - } - } - - tableDataView.setAdapter(new ListViewAdapter(dataRowList)); - tableDataView.setOnItemClickListener(new onClickListenerRow()); + final int startOffset = maxSize * selectedSubpageNr; + final int endOffset = Math.min(startOffset + maxSize + 1, scaleMeasurementList.size()); + adapter.setMeasurements(visibleMeasurements, scaleMeasurementList.subList(startOffset, endOffset), maxSize); } private int pxImageDp(float dp) { @@ -311,14 +278,11 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { private class onClickListenerRow implements AdapterView.OnItemClickListener { @Override - public void onItemClick(AdapterView parent, View view, int position, long click_id) { - LinearLayout dataRow = (LinearLayout)view; - TextView idTextView = (TextView) dataRow.getChildAt(0); - int id = Integer.parseInt(idTextView.getText().toString()); - + public void onItemClick(AdapterView parent, View view, int position, long id) { Intent intent = new Intent(tableView.getContext(), DataEntryActivity.class); - intent.putExtra(DataEntryActivity.EXTRA_ID, id); - startActivityForResult(intent, 1); } + intent.putExtra(DataEntryActivity.EXTRA_ID, (int)id); + startActivityForResult(intent, 1); + } } private void importTable() { @@ -480,69 +444,102 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { private class ListViewAdapter extends BaseAdapter { - private ArrayList> dataList; - private LinearLayout row; + private List visibleMeasurements; + private List scaleMeasurements; + private int measurementsToShow = 0; - public ListViewAdapter(ArrayList> list) { - super(); - this.dataList = list; + private Spanned[][] stringCache; + + private ArrayList> dataList; + + public void setMeasurements(List visibleMeasurements, + List scaleMeasurements, + int maxSize) { + this.visibleMeasurements = visibleMeasurements; + this.scaleMeasurements = scaleMeasurements; + measurementsToShow = Math.min(scaleMeasurements.size(), maxSize); + + stringCache = new Spanned[measurementsToShow][visibleMeasurements.size()]; + + notifyDataSetChanged(); } @Override public int getCount() { - return dataList.size(); + return measurementsToShow; } @Override public Object getItem(int position) { - return dataList.get(position); + return scaleMeasurements.get(position); } @Override public long getItemId(int position) { - return 0; + return scaleMeasurements.get(position).getId(); } @Override public View getView(int position, View convertView, ViewGroup parent) { - if (dataList.isEmpty()) { - return convertView; - } + // Create entries in stringCache if needed + if (stringCache[position][0] == null) { + ScaleMeasurement measurement = scaleMeasurements.get(position); + ScaleMeasurement prevMeasurement = null; + if (position + 1 < scaleMeasurements.size()) { + prevMeasurement = scaleMeasurements.get(position + 1); + } - if (convertView == null) { - row = new LinearLayout(getContext()); - convertView = row; + for (int i = 0; i < visibleMeasurements.size(); ++i) { + visibleMeasurements.get(i).loadFrom(measurement, prevMeasurement); - for (int i = 0; i< dataList.get(0).size(); i++) { - TextView column = new TextView(getContext()); - column.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1)); - column.getLayoutParams().width = 0; - column.setGravity(Gravity.CENTER); + SpannableStringBuilder string = new SpannableStringBuilder(); + string.append(visibleMeasurements.get(i).getValueAsString()); + string.append("\n"); + visibleMeasurements.get(i).appendDiffValue(string); - if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_XLARGE && - (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_LARGE) { - column.setTextSize(COMPLEX_UNIT_DIP, 9); - } - - if (i == 0) { - column.setVisibility(View.GONE); - } - - row.addView(column); + stringCache[position][i] = string; } } - LinearLayout convView = (LinearLayout)convertView; + // Create view if needed + LinearLayout row; + if (convertView == null) { + row = new LinearLayout(getContext()); - HashMap map = dataList.get(position); + final int screenSize = getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK; + final boolean isSmallScreen = + screenSize != Configuration.SCREENLAYOUT_SIZE_XLARGE + && screenSize != Configuration.SCREENLAYOUT_SIZE_LARGE; - for (int i = 0; i < map.size(); i++) { - TextView column = (TextView)convView.getChildAt(i); - column.setText(map.get(i)); + for (int i = 0; i < visibleMeasurements.size(); ++i) { + TextView column = new TextView(getContext()); + column.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1)); + column.getLayoutParams().width = 0; + column.setGravity(Gravity.CENTER); + + if (isSmallScreen) { + column.setTextSize(COMPLEX_UNIT_DIP, 9); + } + row.addView(column); + } + } + else { + row = (LinearLayout) convertView; } - return convertView; + // Fill view with data + for (int i = 0; i < visibleMeasurements.size(); ++i) { + TextView column = (TextView) row.getChildAt(i); + column.setText(stringCache[position][i]); + } + + return row; } + @Override + public boolean hasStableIds() { + return true; + } } } From 9d9611ac72bf45b59351c2e91e2fe817011a8ef7 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Thu, 8 Feb 2018 21:46:21 +0100 Subject: [PATCH 2/8] Add new line in appendDiffValue so that it's only added when needed (i.e. when there are a diff value). --- .../java/com/health/openscale/gui/fragments/TableFragment.java | 1 - .../com/health/openscale/gui/views/FloatMeasurementView.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index 8695693f..630a9797 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -494,7 +494,6 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { SpannableStringBuilder string = new SpannableStringBuilder(); string.append(visibleMeasurements.get(i).getValueAsString()); - string.append("\n"); visibleMeasurements.get(i).appendDiffValue(string); stringCache[position][i] = string; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java index b0ec0bfa..166ea1a3 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java @@ -286,6 +286,7 @@ public abstract class FloatMeasurementView extends MeasurementView { color = Color.GRAY; } + text.append('\n'); int start = text.length(); text.append(symbol); text.setSpan(new ForegroundColorSpan(color), start, text.length(), From 8b3461c2b8fcd5e53f3a817e50ad8b9084662970 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Mon, 12 Feb 2018 22:10:03 +0100 Subject: [PATCH 3/8] Add a bit of space around the edges --- android_app/app/src/main/res/layout/fragment_table.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android_app/app/src/main/res/layout/fragment_table.xml b/android_app/app/src/main/res/layout/fragment_table.xml index 49c8d12f..39f9ed3c 100644 --- a/android_app/app/src/main/res/layout/fragment_table.xml +++ b/android_app/app/src/main/res/layout/fragment_table.xml @@ -69,7 +69,8 @@ + android:layout_height="match_parent" + android:layout_marginHorizontal="5dp"> From f2d7b355a8eb908410bc0aef59a6dd7b644c7ce3 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Mon, 12 Feb 2018 22:12:11 +0100 Subject: [PATCH 4/8] Make all table entries at least two lines high --- .../openscale/gui/fragments/TableFragment.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index 630a9797..455b40be 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -512,10 +512,14 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { for (int i = 0; i < visibleMeasurements.size(); ++i) { TextView column = new TextView(getContext()); - column.setLayoutParams(new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1)); - column.getLayoutParams().width = 0; - column.setGravity(Gravity.CENTER); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT, + 1); + layoutParams.width = 0; + column.setLayoutParams(layoutParams); + column.setMinLines(2); + column.setGravity(Gravity.CENTER_HORIZONTAL); if (isSmallScreen) { column.setTextSize(COMPLEX_UNIT_DIP, 9); From b9f4c7de8ee8adabe4181023dbd55803cb41284d Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Mon, 12 Feb 2018 23:13:18 +0100 Subject: [PATCH 5/8] Use a file provider to implement sharing --- android_app/app/src/main/AndroidManifest.xml | 10 ++++++ .../gui/fragments/TableFragment.java | 31 +++++++++---------- .../app/src/main/res/values/strings.xml | 1 + .../src/main/res/xml/file_provider_paths.xml | 4 +++ 4 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 android_app/app/src/main/res/xml/file_provider_paths.xml diff --git a/android_app/app/src/main/AndroidManifest.xml b/android_app/app/src/main/AndroidManifest.xml index 2688f0e8..28ba58a6 100644 --- a/android_app/app/src/main/AndroidManifest.xml +++ b/android_app/app/src/main/AndroidManifest.xml @@ -34,6 +34,16 @@ + + + + diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index 455b40be..ee8c45f7 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -29,6 +29,7 @@ import android.os.Environment; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; +import android.support.v4.content.FileProvider; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.view.Gravity; @@ -49,6 +50,7 @@ import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; +import com.health.openscale.BuildConfig; import com.health.openscale.R; import com.health.openscale.core.OpenScale; import com.health.openscale.core.datatypes.ScaleMeasurement; @@ -169,9 +171,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { } return true; case R.id.shareData: - if (PermissionHelper.requestWritePermission(getActivity())) { - shareTable(); - } + shareTable(); return true; default: return false; @@ -368,26 +368,25 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { private void shareTable() { final ScaleUser selectedScaleUser = OpenScale.getInstance(getContext()).getSelectedScaleUser(); - String exportFilename = prefs.getString("exportFilename" + selectedScaleUser.getId(), "openScale_data_" + selectedScaleUser.getUserName() + ".csv"); - String fullPath = Environment.getExternalStorageDirectory().getPath() + "/tmp/" + exportFilename; - - if (!OpenScale.getInstance(getContext()).exportData(fullPath)) { + File shareFile = new File(getContext().getCacheDir(), + String.format("openScale %s.csv", selectedScaleUser.getUserName())); + if (!OpenScale.getInstance(getContext()).exportData(shareFile.getPath())) { return; } - Intent intentShareFile = new Intent(Intent.ACTION_SEND); - File shareFile = new File(fullPath); + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType("text/csv"); - if(shareFile.exists()) { - intentShareFile.setType("text/comma-separated-values"); - intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+fullPath)); + final Uri uri = FileProvider.getUriForFile( + getContext(), BuildConfig.APPLICATION_ID + ".fileprovider", shareFile); + intent.putExtra(Intent.EXTRA_STREAM, uri); - intentShareFile.putExtra(Intent.EXTRA_SUBJECT, "openScale export csv file"); - intentShareFile.putExtra(Intent.EXTRA_TEXT, exportFilename); + intent.putExtra(Intent.EXTRA_SUBJECT, + getResources().getString(R.string.label_share_subject, selectedScaleUser.getUserName())); - startActivity(Intent.createChooser(intentShareFile, getResources().getString(R.string.label_share))); - } + startActivity(Intent.createChooser(intent, getResources().getString(R.string.label_share))); } @Override diff --git a/android_app/app/src/main/res/values/strings.xml b/android_app/app/src/main/res/values/strings.xml index 3b26ccb7..4b2e84b1 100644 --- a/android_app/app/src/main/res/values/strings.xml +++ b/android_app/app/src/main/res/values/strings.xml @@ -25,6 +25,7 @@ Delete Add user Share + openScale CSV data export (%s) Id Weight diff --git a/android_app/app/src/main/res/xml/file_provider_paths.xml b/android_app/app/src/main/res/xml/file_provider_paths.xml new file mode 100644 index 00000000..b7974d83 --- /dev/null +++ b/android_app/app/src/main/res/xml/file_provider_paths.xml @@ -0,0 +1,4 @@ + + + + From 33a6a365fe384267b85b6bee149864ba8c4c3555 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Mon, 12 Feb 2018 23:33:26 +0100 Subject: [PATCH 6/8] Don't call startActivityForResult when no result is needed --- .../src/main/java/com/health/openscale/gui/MainActivity.java | 4 ++-- .../com/health/openscale/gui/fragments/GraphFragment.java | 2 +- .../com/health/openscale/gui/fragments/TableFragment.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java index 3b985c90..c53dd7ce 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java @@ -279,7 +279,7 @@ public class MainActivity extends AppCompatActivity { case R.id.nav_settings: Intent settingsIntent = new Intent(this, SettingsActivity.class); settingsIntent.putExtra(SettingsActivity.EXTRA_TINT_COLOR, navDrawer.getItemTextColor().getDefaultColor()); - startActivityForResult(settingsIntent, 1); + startActivity(settingsIntent); return; case R.id.nav_help: startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/oliexdev/openScale/wiki"))); @@ -336,7 +336,7 @@ public class MainActivity extends AppCompatActivity { return true; case R.id.action_add_measurement: Intent intent = new Intent(getApplicationContext(), DataEntryActivity.class); - startActivityForResult(intent, 1); + startActivity(intent); return true; case R.id.action_bluetooth_status: invokeSearchBluetoothDevice(); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java index 829e54b2..b2cd7aa2 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java @@ -640,7 +640,7 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { Intent intent = new Intent(graphView.getContext(), DataEntryActivity.class); intent.putExtra(DataEntryActivity.EXTRA_ID, id); - startActivityForResult(intent, 1); + startActivity(intent); } @Override diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index ee8c45f7..6f0b2a2d 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -281,7 +281,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { public void onItemClick(AdapterView parent, View view, int position, long id) { Intent intent = new Intent(tableView.getContext(), DataEntryActivity.class); intent.putExtra(DataEntryActivity.EXTRA_ID, (int)id); - startActivityForResult(intent, 1); + startActivity(intent); } } From 979638bc2f137f525d975ce6c12443dbb8802891 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Tue, 13 Feb 2018 19:35:33 +0100 Subject: [PATCH 7/8] Handle CSV import of empty file --- .../java/com/health/openscale/core/utils/CsvHelper.java | 4 ++++ .../src/test/java/com/health/openscale/CsvHelperTest.java | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/android_app/app/src/main/java/com/health/openscale/core/utils/CsvHelper.java b/android_app/app/src/main/java/com/health/openscale/core/utils/CsvHelper.java index 5403be3f..77161fa8 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/utils/CsvHelper.java +++ b/android_app/app/src/main/java/com/health/openscale/core/utils/CsvHelper.java @@ -33,6 +33,10 @@ public class CsvHelper { } private static String[] getOldStyleHeaders(String sampleLine) { + if (sampleLine == null) { + return null; + } + final String[] fields = sampleLine.split(",", -1); // Return an array with header fields so that all the headers that actually are diff --git a/android_app/app/src/test/java/com/health/openscale/CsvHelperTest.java b/android_app/app/src/test/java/com/health/openscale/CsvHelperTest.java index d801bcb5..d881759b 100644 --- a/android_app/app/src/test/java/com/health/openscale/CsvHelperTest.java +++ b/android_app/app/src/test/java/com/health/openscale/CsvHelperTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import java.io.BufferedReader; import java.io.StringReader; import java.io.StringWriter; +import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.List; @@ -181,4 +182,10 @@ public class CsvHelperTest { assertEquals(1, list.size()); validateEntry(list.get(0), 0); } + + @Test(expected = ParseException.class) + public void empty() throws Exception { + final String data = ""; + CsvHelper.importFrom(new BufferedReader(new StringReader(data))); + } } From 930630883c20bcf235a35ff081e8e82e8b0f5898 Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Tue, 13 Feb 2018 21:12:10 +0100 Subject: [PATCH 8/8] Use intent to open file for import --- .../com/health/openscale/core/OpenScale.java | 26 ++++++-- .../gui/fragments/TableFragment.java | 59 +++++++------------ 2 files changed, 42 insertions(+), 43 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java b/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java index e3b70b9d..21b47b5f 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java +++ b/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java @@ -21,8 +21,11 @@ import android.arch.persistence.room.Room; import android.arch.persistence.room.RoomDatabase; import android.content.Context; import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; import android.os.Handler; import android.preference.PreferenceManager; +import android.provider.OpenableColumns; import android.support.v4.app.Fragment; import android.text.format.DateFormat; import android.util.Log; @@ -46,9 +49,10 @@ import com.health.openscale.core.utils.CsvHelper; import com.health.openscale.gui.fragments.FragmentUpdateListener; import java.io.BufferedReader; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; @@ -328,10 +332,20 @@ public class OpenScale { updateScaleData(); } - public void importData(String filename) { + private String getFilenameFromUri(Uri uri) { + Cursor cursor = context.getContentResolver().query( + uri, null, null, null, null); + cursor.moveToFirst(); + return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + } + + public void importData(Uri uri) { try { + final String filename = getFilenameFromUri(uri); + + InputStream input = context.getContentResolver().openInputStream(uri); List csvScaleMeasurementList = - CsvHelper.importFrom(new BufferedReader(new FileReader(filename))); + CsvHelper.importFrom(new BufferedReader(new InputStreamReader(input))); final int userId = getSelectedScaleUser().getId(); for (ScaleMeasurement measurement : csvScaleMeasurementList) { @@ -340,11 +354,11 @@ public class OpenScale { measurementDAO.insertAll(csvScaleMeasurementList); updateScaleData(); - Toast.makeText(context, context.getString(R.string.info_data_imported) + " /sdcard" + filename, Toast.LENGTH_SHORT).show(); + Toast.makeText(context, context.getString(R.string.info_data_imported) + " " + filename, Toast.LENGTH_SHORT).show(); } catch (IOException e) { - Toast.makeText(context, context.getString(R.string.error_importing) + e.getMessage(), Toast.LENGTH_SHORT).show(); + Toast.makeText(context, context.getString(R.string.error_importing) + ": " + e.getMessage(), Toast.LENGTH_SHORT).show(); } catch (ParseException e) { - Toast.makeText(context, context.getString(R.string.error_importing) + e.getMessage(), Toast.LENGTH_SHORT).show(); + Toast.makeText(context, context.getString(R.string.error_importing) + ": " + e.getMessage(), Toast.LENGTH_SHORT).show(); } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index 6f0b2a2d..369f7e15 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -79,6 +79,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import static android.app.Activity.RESULT_OK; import static android.util.TypedValue.COMPLEX_UNIT_DIP; public class TableFragment extends Fragment implements FragmentUpdateListener { @@ -94,7 +95,9 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { private ArrayList measurementsList; private int selectedSubpageNr; - private static String SELECTED_SUBPAGE_NR_KEY = "selectedSubpageNr"; + private static final String SELECTED_SUBPAGE_NR_KEY = "selectedSubpageNr"; + + private static final int IMPORT_DATA_REQUEST = 100; public TableFragment() { @@ -158,12 +161,9 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { @Override public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { case R.id.importData: - if (PermissionHelper.requestReadPermission(getActivity())) { - importTable(); - } + importTable(); return true; case R.id.exportData: if (PermissionHelper.requestWritePermission(getActivity())) { @@ -285,11 +285,19 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == IMPORT_DATA_REQUEST && resultCode == RESULT_OK && data != null) { + OpenScale.getInstance(getContext()).importData(data.getData()); + } + } + private void importTable() { int selectedUserId = OpenScale.getInstance(getContext()).getSelectedScaleUserId(); - if (selectedUserId == -1) - { + if (selectedUserId == -1) { AlertDialog.Builder infoDialog = new AlertDialog.Builder(getContext()); infoDialog.setMessage(getResources().getString(R.string.info_no_selected_user)); @@ -298,36 +306,14 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { infoDialog.show(); } - else - { - AlertDialog.Builder filenameDialog = new AlertDialog.Builder(getActivity()); + else { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("text/*"); - filenameDialog.setTitle(getResources().getString(R.string.info_set_filename) + " /sdcard ..."); - - String exportFilename = prefs.getString("exportFilename", "/openScale_data_" + OpenScale.getInstance(getContext()).getSelectedScaleUser().getUserName() + ".csv"); - - final EditText txtFilename = new EditText(tableView.getContext()); - txtFilename.setText(exportFilename); - - filenameDialog.setView(txtFilename); - - filenameDialog.setPositiveButton(getResources().getString(R.string.label_ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - OpenScale.getInstance(getContext()).importData(Environment.getExternalStorageDirectory().getPath() + txtFilename.getText().toString()); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(tableView.getContext()); - prefs.edit().putString("exportFilename", txtFilename.getText().toString()).commit(); - updateOnView(OpenScale.getInstance(getContext()).getScaleMeasurementList()); - } - }); - - filenameDialog.setNegativeButton(getResources().getString(R.string.label_cancel), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - } - }); - - - filenameDialog.show(); + startActivityForResult( + Intent.createChooser(intent, getResources().getString(R.string.label_import)), + IMPORT_DATA_REQUEST); } } @@ -365,7 +351,6 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { filenameDialog.show(); } - private void shareTable() { final ScaleUser selectedScaleUser = OpenScale.getInstance(getContext()).getSelectedScaleUser();