mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-31 20:11:58 +02:00
@@ -34,6 +34,16 @@
|
|||||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="android.support.v4.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:grantUriPermissions="true"
|
||||||
|
android:exported="false">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_provider_paths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@@ -21,8 +21,11 @@ import android.arch.persistence.room.Room;
|
|||||||
import android.arch.persistence.room.RoomDatabase;
|
import android.arch.persistence.room.RoomDatabase;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -46,9 +49,10 @@ import com.health.openscale.core.utils.CsvHelper;
|
|||||||
import com.health.openscale.gui.fragments.FragmentUpdateListener;
|
import com.health.openscale.gui.fragments.FragmentUpdateListener;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@@ -328,10 +332,20 @@ public class OpenScale {
|
|||||||
updateScaleData();
|
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 {
|
try {
|
||||||
|
final String filename = getFilenameFromUri(uri);
|
||||||
|
|
||||||
|
InputStream input = context.getContentResolver().openInputStream(uri);
|
||||||
List<ScaleMeasurement> csvScaleMeasurementList =
|
List<ScaleMeasurement> csvScaleMeasurementList =
|
||||||
CsvHelper.importFrom(new BufferedReader(new FileReader(filename)));
|
CsvHelper.importFrom(new BufferedReader(new InputStreamReader(input)));
|
||||||
|
|
||||||
final int userId = getSelectedScaleUser().getId();
|
final int userId = getSelectedScaleUser().getId();
|
||||||
for (ScaleMeasurement measurement : csvScaleMeasurementList) {
|
for (ScaleMeasurement measurement : csvScaleMeasurementList) {
|
||||||
@@ -340,11 +354,11 @@ public class OpenScale {
|
|||||||
|
|
||||||
measurementDAO.insertAll(csvScaleMeasurementList);
|
measurementDAO.insertAll(csvScaleMeasurementList);
|
||||||
updateScaleData();
|
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) {
|
} 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) {
|
} 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,10 @@ public class CsvHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String[] getOldStyleHeaders(String sampleLine) {
|
private static String[] getOldStyleHeaders(String sampleLine) {
|
||||||
|
if (sampleLine == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final String[] fields = sampleLine.split(",", -1);
|
final String[] fields = sampleLine.split(",", -1);
|
||||||
|
|
||||||
// Return an array with header fields so that all the headers that actually are
|
// Return an array with header fields so that all the headers that actually are
|
||||||
|
@@ -279,7 +279,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
case R.id.nav_settings:
|
case R.id.nav_settings:
|
||||||
Intent settingsIntent = new Intent(this, SettingsActivity.class);
|
Intent settingsIntent = new Intent(this, SettingsActivity.class);
|
||||||
settingsIntent.putExtra(SettingsActivity.EXTRA_TINT_COLOR, navDrawer.getItemTextColor().getDefaultColor());
|
settingsIntent.putExtra(SettingsActivity.EXTRA_TINT_COLOR, navDrawer.getItemTextColor().getDefaultColor());
|
||||||
startActivityForResult(settingsIntent, 1);
|
startActivity(settingsIntent);
|
||||||
return;
|
return;
|
||||||
case R.id.nav_help:
|
case R.id.nav_help:
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/oliexdev/openScale/wiki")));
|
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;
|
return true;
|
||||||
case R.id.action_add_measurement:
|
case R.id.action_add_measurement:
|
||||||
Intent intent = new Intent(getApplicationContext(), DataEntryActivity.class);
|
Intent intent = new Intent(getApplicationContext(), DataEntryActivity.class);
|
||||||
startActivityForResult(intent, 1);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_bluetooth_status:
|
case R.id.action_bluetooth_status:
|
||||||
invokeSearchBluetoothDevice();
|
invokeSearchBluetoothDevice();
|
||||||
|
@@ -640,7 +640,7 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
Intent intent = new Intent(graphView.getContext(), DataEntryActivity.class);
|
Intent intent = new Intent(graphView.getContext(), DataEntryActivity.class);
|
||||||
intent.putExtra(DataEntryActivity.EXTRA_ID, id);
|
intent.putExtra(DataEntryActivity.EXTRA_ID, id);
|
||||||
startActivityForResult(intent, 1);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -29,9 +29,9 @@ import android.os.Environment;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.SpannedString;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -50,6 +50,7 @@ import android.widget.TableRow;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.health.openscale.BuildConfig;
|
||||||
import com.health.openscale.R;
|
import com.health.openscale.R;
|
||||||
import com.health.openscale.core.OpenScale;
|
import com.health.openscale.core.OpenScale;
|
||||||
import com.health.openscale.core.datatypes.ScaleMeasurement;
|
import com.health.openscale.core.datatypes.ScaleMeasurement;
|
||||||
@@ -78,6 +79,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||||
|
|
||||||
public class TableFragment extends Fragment implements FragmentUpdateListener {
|
public class TableFragment extends Fragment implements FragmentUpdateListener {
|
||||||
@@ -93,7 +95,9 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
private ArrayList <MeasurementView> measurementsList;
|
private ArrayList <MeasurementView> measurementsList;
|
||||||
|
|
||||||
private int selectedSubpageNr;
|
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() {
|
public TableFragment() {
|
||||||
|
|
||||||
@@ -109,6 +113,9 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
tableDataView = (ListView) tableView.findViewById(R.id.tableDataView);
|
tableDataView = (ListView) tableView.findViewById(R.id.tableDataView);
|
||||||
tableHeaderView = (LinearLayout) tableView.findViewById(R.id.tableHeaderView);
|
tableHeaderView = (LinearLayout) tableView.findViewById(R.id.tableHeaderView);
|
||||||
|
|
||||||
|
tableDataView.setAdapter(new ListViewAdapter());
|
||||||
|
tableDataView.setOnItemClickListener(new onClickListenerRow());
|
||||||
|
|
||||||
optionMenu = (ImageView) tableView.findViewById(R.id.optionMenu);
|
optionMenu = (ImageView) tableView.findViewById(R.id.optionMenu);
|
||||||
|
|
||||||
measurementsList = new ArrayList<>();
|
measurementsList = new ArrayList<>();
|
||||||
@@ -154,12 +161,9 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
|
|
||||||
|
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.importData:
|
case R.id.importData:
|
||||||
if (PermissionHelper.requestReadPermission(getActivity())) {
|
|
||||||
importTable();
|
importTable();
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
case R.id.exportData:
|
case R.id.exportData:
|
||||||
if (PermissionHelper.requestWritePermission(getActivity())) {
|
if (PermissionHelper.requestWritePermission(getActivity())) {
|
||||||
@@ -167,9 +171,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.shareData:
|
case R.id.shareData:
|
||||||
if (PermissionHelper.requestWritePermission(getActivity())) {
|
|
||||||
shareTable();
|
shareTable();
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -192,15 +194,12 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
@Override
|
@Override
|
||||||
public void updateOnView(List<ScaleMeasurement> scaleMeasurementList)
|
public void updateOnView(List<ScaleMeasurement> scaleMeasurementList)
|
||||||
{
|
{
|
||||||
tableDataView.setAdapter(new ListViewAdapter(new ArrayList<HashMap<Integer, Spanned>>())); // delete all data in the table with an empty adapter array list
|
|
||||||
|
|
||||||
if (scaleMeasurementList.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int maxSize = 25;
|
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();
|
subpageView.removeAllViews();
|
||||||
|
|
||||||
@@ -216,7 +215,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
moveSubpageLeft.setEnabled(selectedSubpageNr > 0);
|
moveSubpageLeft.setEnabled(selectedSubpageNr > 0);
|
||||||
subpageView.addView(moveSubpageLeft);
|
subpageView.addView(moveSubpageLeft);
|
||||||
|
|
||||||
for (int i=0; i<subpageCount; i++) {
|
for (int i = 0; i < subpageCount; i++) {
|
||||||
TextView subpageNrView = new TextView(tableView.getContext());
|
TextView subpageNrView = new TextView(tableView.getContext());
|
||||||
subpageNrView.setOnClickListener(new onClickListenerSubpageSelect());
|
subpageNrView.setOnClickListener(new onClickListenerSubpageSelect());
|
||||||
subpageNrView.setText(Integer.toString(i+1));
|
subpageNrView.setText(Integer.toString(i+1));
|
||||||
@@ -225,6 +224,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
subpageView.addView(subpageNrView);
|
subpageView.addView(subpageNrView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subpageView.getChildCount() > 1) {
|
if (subpageView.getChildCount() > 1) {
|
||||||
TextView selectedSubpageNrView = (TextView) subpageView.getChildAt(selectedSubpageNr + 1);
|
TextView selectedSubpageNrView = (TextView) subpageView.getChildAt(selectedSubpageNr + 1);
|
||||||
if (selectedSubpageNrView != null) {
|
if (selectedSubpageNrView != null) {
|
||||||
@@ -247,6 +247,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
tableHeaderView.removeAllViews();
|
tableHeaderView.removeAllViews();
|
||||||
|
|
||||||
|
ArrayList<MeasurementView> visibleMeasurements = new ArrayList<>();
|
||||||
for (MeasurementView measurement : measurementsList) {
|
for (MeasurementView measurement : measurementsList) {
|
||||||
measurement.updatePreferences(prefs);
|
measurement.updatePreferences(prefs);
|
||||||
|
|
||||||
@@ -259,50 +260,16 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
headerIcon.getLayoutParams().height = pxImageDp(20);
|
headerIcon.getLayoutParams().height = pxImageDp(20);
|
||||||
|
|
||||||
tableHeaderView.addView(headerIcon);
|
tableHeaderView.addView(headerIcon);
|
||||||
|
|
||||||
|
visibleMeasurements.add(measurement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<HashMap<Integer, Spanned>> dataRowList = new ArrayList<>();
|
ListViewAdapter adapter = (ListViewAdapter) tableDataView.getAdapter();
|
||||||
|
|
||||||
int displayCount = 0;
|
final int startOffset = maxSize * selectedSubpageNr;
|
||||||
|
final int endOffset = Math.min(startOffset + maxSize + 1, scaleMeasurementList.size());
|
||||||
for (int i = (maxSize * selectedSubpageNr); i < scaleMeasurementList.size(); i++) {
|
adapter.setMeasurements(visibleMeasurements, scaleMeasurementList.subList(startOffset, endOffset), maxSize);
|
||||||
ScaleMeasurement scaleMeasurement = scaleMeasurementList.get(i);
|
|
||||||
|
|
||||||
ScaleMeasurement prevScaleMeasurement = null;
|
|
||||||
if (i < scaleMeasurementList.size() - 1) {
|
|
||||||
prevScaleMeasurement = scaleMeasurementList.get(i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<Integer, Spanned> 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int pxImageDp(float dp) {
|
private int pxImageDp(float dp) {
|
||||||
@@ -311,21 +278,26 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
private class onClickListenerRow implements AdapterView.OnItemClickListener {
|
private class onClickListenerRow implements AdapterView.OnItemClickListener {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long click_id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
LinearLayout dataRow = (LinearLayout)view;
|
|
||||||
TextView idTextView = (TextView) dataRow.getChildAt(0);
|
|
||||||
int id = Integer.parseInt(idTextView.getText().toString());
|
|
||||||
|
|
||||||
Intent intent = new Intent(tableView.getContext(), DataEntryActivity.class);
|
Intent intent = new Intent(tableView.getContext(), DataEntryActivity.class);
|
||||||
intent.putExtra(DataEntryActivity.EXTRA_ID, id);
|
intent.putExtra(DataEntryActivity.EXTRA_ID, (int)id);
|
||||||
startActivityForResult(intent, 1); }
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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() {
|
private void importTable() {
|
||||||
int selectedUserId = OpenScale.getInstance(getContext()).getSelectedScaleUserId();
|
int selectedUserId = OpenScale.getInstance(getContext()).getSelectedScaleUserId();
|
||||||
|
|
||||||
if (selectedUserId == -1)
|
if (selectedUserId == -1) {
|
||||||
{
|
|
||||||
AlertDialog.Builder infoDialog = new AlertDialog.Builder(getContext());
|
AlertDialog.Builder infoDialog = new AlertDialog.Builder(getContext());
|
||||||
|
|
||||||
infoDialog.setMessage(getResources().getString(R.string.info_no_selected_user));
|
infoDialog.setMessage(getResources().getString(R.string.info_no_selected_user));
|
||||||
@@ -334,36 +306,14 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
infoDialog.show();
|
infoDialog.show();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
AlertDialog.Builder filenameDialog = new AlertDialog.Builder(getActivity());
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
intent.setType("text/*");
|
||||||
|
|
||||||
filenameDialog.setTitle(getResources().getString(R.string.info_set_filename) + " /sdcard ...");
|
startActivityForResult(
|
||||||
|
Intent.createChooser(intent, getResources().getString(R.string.label_import)),
|
||||||
String exportFilename = prefs.getString("exportFilename", "/openScale_data_" + OpenScale.getInstance(getContext()).getSelectedScaleUser().getUserName() + ".csv");
|
IMPORT_DATA_REQUEST);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,29 +351,27 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
filenameDialog.show();
|
filenameDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void shareTable() {
|
private void shareTable() {
|
||||||
final ScaleUser selectedScaleUser = OpenScale.getInstance(getContext()).getSelectedScaleUser();
|
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;
|
File shareFile = new File(getContext().getCacheDir(),
|
||||||
|
String.format("openScale %s.csv", selectedScaleUser.getUserName()));
|
||||||
if (!OpenScale.getInstance(getContext()).exportData(fullPath)) {
|
if (!OpenScale.getInstance(getContext()).exportData(shareFile.getPath())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
File shareFile = new File(fullPath);
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
intent.setType("text/csv");
|
||||||
|
|
||||||
if(shareFile.exists()) {
|
final Uri uri = FileProvider.getUriForFile(
|
||||||
intentShareFile.setType("text/comma-separated-values");
|
getContext(), BuildConfig.APPLICATION_ID + ".fileprovider", shareFile);
|
||||||
intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+fullPath));
|
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
|
||||||
intentShareFile.putExtra(Intent.EXTRA_SUBJECT, "openScale export csv file");
|
intent.putExtra(Intent.EXTRA_SUBJECT,
|
||||||
intentShareFile.putExtra(Intent.EXTRA_TEXT, exportFilename);
|
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
|
@Override
|
||||||
@@ -480,69 +428,105 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
private class ListViewAdapter extends BaseAdapter {
|
private class ListViewAdapter extends BaseAdapter {
|
||||||
|
|
||||||
private ArrayList<HashMap<Integer, Spanned>> dataList;
|
private List<MeasurementView> visibleMeasurements;
|
||||||
private LinearLayout row;
|
private List<ScaleMeasurement> scaleMeasurements;
|
||||||
|
private int measurementsToShow = 0;
|
||||||
|
|
||||||
public ListViewAdapter(ArrayList<HashMap<Integer, Spanned>> list) {
|
private Spanned[][] stringCache;
|
||||||
super();
|
|
||||||
this.dataList = list;
|
private ArrayList<HashMap<Integer, Spanned>> dataList;
|
||||||
|
|
||||||
|
public void setMeasurements(List<MeasurementView> visibleMeasurements,
|
||||||
|
List<ScaleMeasurement> scaleMeasurements,
|
||||||
|
int maxSize) {
|
||||||
|
this.visibleMeasurements = visibleMeasurements;
|
||||||
|
this.scaleMeasurements = scaleMeasurements;
|
||||||
|
measurementsToShow = Math.min(scaleMeasurements.size(), maxSize);
|
||||||
|
|
||||||
|
stringCache = new Spanned[measurementsToShow][visibleMeasurements.size()];
|
||||||
|
|
||||||
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return dataList.size();
|
return measurementsToShow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
return dataList.get(position);
|
return scaleMeasurements.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
return 0;
|
return scaleMeasurements.get(position).getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
if (dataList.isEmpty()) {
|
// Create entries in stringCache if needed
|
||||||
return convertView;
|
if (stringCache[position][0] == null) {
|
||||||
|
ScaleMeasurement measurement = scaleMeasurements.get(position);
|
||||||
|
ScaleMeasurement prevMeasurement = null;
|
||||||
|
if (position + 1 < scaleMeasurements.size()) {
|
||||||
|
prevMeasurement = scaleMeasurements.get(position + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < visibleMeasurements.size(); ++i) {
|
||||||
|
visibleMeasurements.get(i).loadFrom(measurement, prevMeasurement);
|
||||||
|
|
||||||
|
SpannableStringBuilder string = new SpannableStringBuilder();
|
||||||
|
string.append(visibleMeasurements.get(i).getValueAsString());
|
||||||
|
visibleMeasurements.get(i).appendDiffValue(string);
|
||||||
|
|
||||||
|
stringCache[position][i] = string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create view if needed
|
||||||
|
LinearLayout row;
|
||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
row = new LinearLayout(getContext());
|
row = new LinearLayout(getContext());
|
||||||
convertView = row;
|
|
||||||
|
|
||||||
for (int i = 0; i< dataList.get(0).size(); i++) {
|
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 < visibleMeasurements.size(); ++i) {
|
||||||
TextView column = new TextView(getContext());
|
TextView column = new TextView(getContext());
|
||||||
column.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
|
||||||
column.getLayoutParams().width = 0;
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
column.setGravity(Gravity.CENTER);
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
1);
|
||||||
|
layoutParams.width = 0;
|
||||||
|
column.setLayoutParams(layoutParams);
|
||||||
|
column.setMinLines(2);
|
||||||
|
column.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||||
|
|
||||||
if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_XLARGE &&
|
if (isSmallScreen) {
|
||||||
(getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_LARGE) {
|
|
||||||
column.setTextSize(COMPLEX_UNIT_DIP, 9);
|
column.setTextSize(COMPLEX_UNIT_DIP, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
column.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
row.addView(column);
|
row.addView(column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
LinearLayout convView = (LinearLayout)convertView;
|
row = (LinearLayout) convertView;
|
||||||
|
|
||||||
HashMap<Integer, Spanned> map = dataList.get(position);
|
|
||||||
|
|
||||||
for (int i = 0; i < map.size(); i++) {
|
|
||||||
TextView column = (TextView)convView.getChildAt(i);
|
|
||||||
column.setText(map.get(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -286,6 +286,7 @@ public abstract class FloatMeasurementView extends MeasurementView {
|
|||||||
color = Color.GRAY;
|
color = Color.GRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
text.append('\n');
|
||||||
int start = text.length();
|
int start = text.length();
|
||||||
text.append(symbol);
|
text.append(symbol);
|
||||||
text.setSpan(new ForegroundColorSpan(color), start, text.length(),
|
text.setSpan(new ForegroundColorSpan(color), start, text.length(),
|
||||||
|
@@ -69,7 +69,8 @@
|
|||||||
<ListView
|
<ListView
|
||||||
android:id="@+id/tableDataView"
|
android:id="@+id/tableDataView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginHorizontal="5dp">
|
||||||
</ListView>
|
</ListView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
<string name="label_delete">Delete</string>
|
<string name="label_delete">Delete</string>
|
||||||
<string name="label_add_user">Add user</string>
|
<string name="label_add_user">Add user</string>
|
||||||
<string name="label_share">Share</string>
|
<string name="label_share">Share</string>
|
||||||
|
<string name="label_share_subject">openScale CSV data export (%s)</string>
|
||||||
|
|
||||||
<string name="label_id">Id</string>
|
<string name="label_id">Id</string>
|
||||||
<string name="label_weight">Weight</string>
|
<string name="label_weight">Weight</string>
|
||||||
|
4
android_app/app/src/main/res/xml/file_provider_paths.xml
Normal file
4
android_app/app/src/main/res/xml/file_provider_paths.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<cache-path name="cache" path="/" />
|
||||||
|
</paths>
|
@@ -24,6 +24,7 @@ import org.junit.Test;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -181,4 +182,10 @@ public class CsvHelperTest {
|
|||||||
assertEquals(1, list.size());
|
assertEquals(1, list.size());
|
||||||
validateEntry(list.get(0), 0);
|
validateEntry(list.get(0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = ParseException.class)
|
||||||
|
public void empty() throws Exception {
|
||||||
|
final String data = "";
|
||||||
|
CsvHelper.importFrom(new BufferedReader(new StringReader(data)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user