From 1feb6befed8cef4b7650401905224c2605f7c2f1 Mon Sep 17 00:00:00 2001 From: OliE Date: Fri, 2 Jan 2015 09:14:10 +0100 Subject: [PATCH] - add buttons to delete single database entries - add settings for disable/enable showing graph lines and graph notes - add icons in multiple sizes to support different screen densities - cleaned up imports --- android_app/app/src/main/AndroidManifest.xml | 2 +- .../core/BluetoothCommunication.java | 11 +- .../com/health/openscale/core/OpenScale.java | 12 +- .../com/health/openscale/core/ScaleData.java | 2 - .../health/openscale/core/ScaleDatabase.java | 58 +++-- .../health/openscale/gui/GraphFragment.java | 94 +++++-- .../health/openscale/gui/MainActivity.java | 8 +- .../openscale/gui/NewEntryActivity.java | 9 +- .../openscale/gui/SettingsActivity.java | 2 - .../health/openscale/gui/TableFragment.java | 244 ++++++++++-------- .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 2039 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1265 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 2633 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 4287 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 6212 bytes .../app/src/main/res/drawable/ic_launcher.png | Bin 17493 -> 0 bytes .../src/main/res/layout/activity_newentry.xml | 25 +- .../src/main/res/layout/fragment_graph.xml | 2 - .../src/main/res/layout/fragment_overview.xml | 6 +- .../src/main/res/layout/fragment_table.xml | 19 +- .../app/src/main/res/values/dimens.xml | 2 +- .../app/src/main/res/values/strings.xml | 19 +- .../app/src/main/res/xml/preferences.xml | 11 +- 23 files changed, 327 insertions(+), 199 deletions(-) create mode 100644 android_app/app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 android_app/app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 android_app/app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 android_app/app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 android_app/app/src/main/res/drawable-xxxhdpi/ic_launcher.png delete mode 100644 android_app/app/src/main/res/drawable/ic_launcher.png diff --git a/android_app/app/src/main/AndroidManifest.xml b/android_app/app/src/main/AndroidManifest.xml index 6d6ecd49..e19ac55e 100644 --- a/android_app/app/src/main/AndroidManifest.xml +++ b/android_app/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionName="1.0" > diff --git a/android_app/app/src/main/java/com/health/openscale/core/BluetoothCommunication.java b/android_app/app/src/main/java/com/health/openscale/core/BluetoothCommunication.java index 6d7c49d6..a2255fb2 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/BluetoothCommunication.java +++ b/android_app/app/src/main/java/com/health/openscale/core/BluetoothCommunication.java @@ -16,19 +16,16 @@ package com.health.openscale.core; -import java.io.IOException; -import java.util.Set; -import java.util.UUID; - import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.os.Handler; -import android.os.Message; -import android.provider.SyncStateContract.Constants; -import android.support.v4.app.FragmentActivity; import android.util.Log; +import java.io.IOException; +import java.util.Set; +import java.util.UUID; + public class BluetoothCommunication extends Thread { public static final int BT_MESSAGE_READ = 0; public static final int BT_SOCKET_CLOSED = 1; 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 c570e6da..e3b3032a 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 @@ -80,6 +80,13 @@ public class OpenScale { scaleDBEntries = scaleDB.getAllDBEntries(); } + public void deleteScaleData(long id) + { + scaleDB.deleteEntry(id); + + scaleDBEntries = scaleDB.getAllDBEntries(); + } + public void importData(String filename) throws IOException { File file = new File(filename); @@ -187,7 +194,7 @@ public class OpenScale { case BluetoothCommunication.BT_SOCKET_CLOSED: scaleDBEntries = scaleDB.getAllDBEntries(); - Log.i("OpenScale", "Socket closed! Restarting socket "); + Log.d("OpenScale", "Socket closed! Restarting socket "); startBluetoothServer(btDeviceName); break; @@ -247,8 +254,7 @@ public class OpenScale { scaleBtData.fat = Float.parseFloat(csvField[7]); scaleBtData.water = Float.parseFloat(csvField[8]); scaleBtData.muscle = Float.parseFloat(csvField[9]); - - Log.i("OpenScale", "MCU Data: " + scaleBtData); + scaleDB.insertEntry(scaleBtData); } else { Log.e("OpenScale", "Error calculated checksum (" + checksum + ") and received checksum (" + btChecksum + ") is different"); diff --git a/android_app/app/src/main/java/com/health/openscale/core/ScaleData.java b/android_app/app/src/main/java/com/health/openscale/core/ScaleData.java index 43329f95..57607458 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/ScaleData.java +++ b/android_app/app/src/main/java/com/health/openscale/core/ScaleData.java @@ -18,8 +18,6 @@ package com.health.openscale.core; import java.util.Date; -import android.util.Log; - public class ScaleData { public long id; public Date date_time; diff --git a/android_app/app/src/main/java/com/health/openscale/core/ScaleDatabase.java b/android_app/app/src/main/java/com/health/openscale/core/ScaleDatabase.java index 5e5c033d..53ae5052 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/ScaleDatabase.java +++ b/android_app/app/src/main/java/com/health/openscale/core/ScaleDatabase.java @@ -19,6 +19,7 @@ package com.health.openscale.core; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; +import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; @@ -27,7 +28,6 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.Locale; public class ScaleDatabase extends SQLiteOpenHelper { @@ -78,25 +78,43 @@ public class ScaleDatabase extends SQLiteOpenHelper { db.delete(TABLE_NAME, null, null); } - public void insertEntry(ScaleData scaleData) { + public boolean insertEntry(ScaleData scaleData) { SQLiteDatabase db = getWritableDatabase(); - - // Create a new map of values, where column names are the keys - ContentValues values = new ContentValues(); - values.put(COLUMN_NAME_DATE_TIME, formatDateTime.format(scaleData.date_time)); - values.put(COLUMN_NAME_WEIGHT, scaleData.weight); - values.put(COLUMN_NAME_FAT, scaleData.fat); - values.put(COLUMN_NAME_WATER, scaleData.water); - values.put(COLUMN_NAME_MUSCLE, scaleData.muscle); - // Insert the new row, returning the primary key value of the new row - long newRowId = db.insert(TABLE_NAME, null, values); - - if (newRowId == -1) { - Log.e("ScaleDatabase", "An error occured while inserting a new entry into the scale database"); - } + Cursor cursorScaleDB = db.query(TABLE_NAME, new String[] {COLUMN_NAME_DATE_TIME}, COLUMN_NAME_DATE_TIME + " = ?", + new String[] {formatDateTime.format(scaleData.date_time)}, null, null, null); + + if (cursorScaleDB.getCount() > 0) { + // we don't want double entries + return false; + } else { + ContentValues values = new ContentValues(); + values.put(COLUMN_NAME_DATE_TIME, formatDateTime.format(scaleData.date_time)); + values.put(COLUMN_NAME_WEIGHT, scaleData.weight); + values.put(COLUMN_NAME_FAT, scaleData.fat); + values.put(COLUMN_NAME_WATER, scaleData.water); + values.put(COLUMN_NAME_MUSCLE, scaleData.muscle); + + try + { + db.insertOrThrow(TABLE_NAME, null, values); + } + catch (SQLException e) + { + Log.e("ScaleDatabase", "An error occured while inserting a new entry into the scale database: " + e.toString()); + return false; + } + } + + return true; } + public void deleteEntry(long id) { + SQLiteDatabase db = getWritableDatabase(); + + db.delete(TABLE_NAME, COLUMN_NAME_ID + "= ?", new String[] {String.valueOf(id)}); + } + public int[] getCountsOfAllMonth(int year) { int [] numOfMonth = new int[12]; @@ -174,9 +192,7 @@ public class ScaleDatabase extends SQLiteOpenHelper { dataEntry.water = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_WATER)); dataEntry.muscle = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_MUSCLE)); - Date date = formatDateTime.parse(date_time); - - dataEntry.date_time = date; + dataEntry.date_time = formatDateTime.parse(date_time); scaleDBEntries.add(dataEntry); @@ -230,9 +246,7 @@ public class ScaleDatabase extends SQLiteOpenHelper { dataEntry.water = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_WATER)); dataEntry.muscle = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_MUSCLE)); - Date date = formatDateTime.parse(date_time); - - dataEntry.date_time = date; + dataEntry.date_time = formatDateTime.parse(date_time); scaleDBEntries.add(dataEntry); //Log.d("ScaleDatabase", dataEntry.toString()); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/GraphFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/GraphFragment.java index 4d69f911..bc22f154 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/GraphFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/GraphFragment.java @@ -16,13 +16,16 @@ package com.health.openscale.gui; +import android.content.SharedPreferences; import android.graphics.Color; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import android.widget.Toast; import com.health.openscale.R; import com.health.openscale.core.OpenScale; @@ -54,15 +57,21 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { private LineChartView chartTop; private ColumnChartView chartBottom; private TextView txtYear; + private SharedPreferences prefs; private OpenScale openScale; private Calendar yearCal; + private ArrayList scaleDBEntries; + + private enum lines {WEIGHT, FAT, WATER, MUSCLE} + private ArrayList activeLines; + public GraphFragment() { yearCal = Calendar.getInstance(); - } - + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -71,6 +80,9 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { chartTop = (LineChartView) graphView.findViewById(R.id.chart_top); chartBottom = (ColumnChartView) graphView.findViewById(R.id.chart_bottom); + chartTop.setOnValueTouchListener(new ChartTopValueTouchListener()); + chartBottom.setOnValueTouchListener(new ChartBottomValueTouchListener()); + txtYear = (TextView) graphView.findViewById(R.id.txtYear); txtYear.setText(Integer.toString(yearCal.get(Calendar.YEAR))); @@ -91,6 +103,8 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { }); openScale = OpenScale.getInstance(graphView.getContext()); + prefs = PreferenceManager.getDefaultSharedPreferences(graphView.getContext()); + return graphView; } @@ -102,7 +116,7 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { private void generateLineData(Calendar cal) { - ArrayList scaleDBEntries = openScale.getAllDataOfMonth(yearCal.get(Calendar.YEAR), cal.get(Calendar.MONTH)); + scaleDBEntries = openScale.getAllDataOfMonth(yearCal.get(Calendar.YEAR), cal.get(Calendar.MONTH)); SimpleDateFormat day_date = new SimpleDateFormat("dd", Locale.getDefault()); @@ -131,38 +145,55 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { { calDB.setTime(scaleEntry.date_time); - valuesWeight.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH), scaleEntry.weight)); - valuesFat.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH), scaleEntry.fat)); - valuesWater.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH), scaleEntry.water)); - valuesMuscle.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH), scaleEntry.muscle)); + valuesWeight.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH)-1, scaleEntry.weight)); + valuesFat.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH)-1, scaleEntry.fat)); + valuesWater.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH)-1, scaleEntry.water)); + valuesMuscle.add(new PointValue(calDB.get(Calendar.DAY_OF_MONTH)-1, scaleEntry.muscle)); } Line lineWeight = new Line(valuesWeight). setColor(Utils.COLOR_VIOLET). setCubic(true). - setHasLabels(true). + setHasLabels(prefs.getBoolean("labelsEnable", true)). setFormatter(new SimpleValueFormatter(1, false, null, null)); Line lineFat = new Line(valuesFat). setColor(Utils.COLOR_ORANGE). setCubic(true). - setHasLabels(true). + setHasLabels(prefs.getBoolean("labelsEnable", true)). setFormatter(new SimpleValueFormatter(1, false, null, null)); Line lineWater = new Line(valuesWater). setColor(Utils.COLOR_BLUE). setCubic(true). - setHasLabels(true). + setHasLabels(prefs.getBoolean("labelsEnable", true)). setFormatter(new SimpleValueFormatter(1, false, null, null)); Line lineMuscle = new Line(valuesMuscle). setColor(Utils.COLOR_GREEN). setCubic(true). - setHasLabels(true). + setHasLabels(prefs.getBoolean("labelsEnable", true)). setFormatter(new SimpleValueFormatter(1, false, null, null)); - lines.add(lineWeight); - lines.add(lineFat); - lines.add(lineWater); - lines.add(lineMuscle); + activeLines = new ArrayList(); + + if(prefs.getBoolean("weightEnable", true)) { + lines.add(lineWeight); + activeLines.add(GraphFragment.lines.WEIGHT); + } + + if(prefs.getBoolean("fatEnable", true)) { + lines.add(lineFat); + activeLines.add(GraphFragment.lines.FAT); + } + + if(prefs.getBoolean("waterEnable", true)) { + lines.add(lineWater); + activeLines.add(GraphFragment.lines.WATER); + } + + if(prefs.getBoolean("muscleEnable", true)) { + lines.add(lineMuscle); + activeLines.add(GraphFragment.lines.MUSCLE); + } LineChartData lineData = new LineChartData(lines); lineData.setAxisXBottom(new Axis(axisValues). @@ -219,12 +250,11 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { chartBottom.setColumnChartData(columnData); chartBottom.setValueSelectionEnabled(true); chartBottom.setZoomType(ZoomType.HORIZONTAL); - chartBottom.setOnValueTouchListener(new ValueTouchListener()); generateLineData(cal); } - private class ValueTouchListener implements ColumnChartView.ColumnChartOnValueTouchListener { + private class ChartBottomValueTouchListener implements ColumnChartView.ColumnChartOnValueTouchListener { @Override public void onValueTouched(int selectedLine, int selectedValue, ColumnValue value) { Calendar cal = Calendar.getInstance(); @@ -239,4 +269,34 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { } } + + private class ChartTopValueTouchListener implements LineChartView.LineChartOnValueTouchListener { + @Override + public void onValueTouched(int lineIndex, int pointIndex, PointValue pointValue) { + ScaleData scaleEntry = scaleDBEntries.get(pointIndex); + lines selectedLine = activeLines.get(lineIndex); + + String date_time = new SimpleDateFormat("dd. MMM yyyy (EE) HH:mm").format(scaleEntry.date_time); + + switch (selectedLine) { + case WEIGHT: + Toast.makeText(getActivity(), getResources().getString(R.string.info_your_weight) + " " + scaleEntry.weight + getResources().getString(R.string.weight_unit) + " " + getResources().getString(R.string.info_on_date) + " " + date_time, Toast.LENGTH_SHORT).show(); + break; + case FAT: + Toast.makeText(getActivity(), getResources().getString(R.string.info_your_fat) + " " + scaleEntry.fat + "% " + getResources().getString(R.string.info_on_date) + " " + date_time, Toast.LENGTH_SHORT).show(); + break; + case WATER: + Toast.makeText(getActivity(), getResources().getString(R.string.info_your_water) + " " + scaleEntry.water + "% " + getResources().getString(R.string.info_on_date) + " " + date_time, Toast.LENGTH_SHORT).show(); + break; + case MUSCLE: + Toast.makeText(getActivity(), getResources().getString(R.string.info_your_muscle) + " " + scaleEntry.muscle + "% " + getResources().getString(R.string.info_on_date) + " " + date_time, Toast.LENGTH_SHORT).show(); + break; + } + } + + @Override + public void onNothingTouched() { + + } + } } 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 035d2aa0..d90f4dca 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 @@ -16,9 +16,6 @@ package com.health.openscale.gui; -import java.util.Locale; - -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; @@ -30,13 +27,14 @@ import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import com.health.openscale.R; import com.health.openscale.core.OpenScale; +import java.util.Locale; + public class MainActivity extends ActionBarActivity implements ActionBar.TabListener { @@ -62,7 +60,7 @@ public class MainActivity extends ActionBarActivity implements setContentView(R.layout.activity_main); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - if(prefs.getBoolean("btEnable", true)) { + if(prefs.getBoolean("btEnable", false)) { String deviceName = prefs.getString("btDeviceName", "openScale"); OpenScale.getInstance(getApplicationContext()).startBluetoothServer(deviceName); } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/NewEntryActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/NewEntryActivity.java index 73b1a49d..3d69faba 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/NewEntryActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/NewEntryActivity.java @@ -15,16 +15,11 @@ */ package com.health.openscale.gui; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; - import android.app.Activity; import android.app.DatePickerDialog; import android.app.TimePickerDialog; import android.content.Context; import android.os.Bundle; -import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.Button; import android.widget.DatePicker; @@ -34,6 +29,10 @@ import android.widget.TimePicker; import com.health.openscale.R; import com.health.openscale.core.OpenScale; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + public class NewEntryActivity extends Activity { private EditText txtWeight; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/SettingsActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/SettingsActivity.java index 3448c14a..d5b7d11d 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/SettingsActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/SettingsActivity.java @@ -15,7 +15,6 @@ */ package com.health.openscale.gui; -import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; @@ -26,7 +25,6 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceGroup; import android.preference.PreferenceManager; -import android.util.Log; import com.health.openscale.R; import com.health.openscale.core.OpenScale; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/TableFragment.java index 3892014c..2f826cd9 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/TableFragment.java @@ -18,10 +18,12 @@ package com.health.openscale.gui; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.Fragment; import android.util.TypedValue; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -56,23 +58,11 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { tableDataView = (TableLayout) tableView.findViewById(R.id.tableDataView); - tableView.findViewById(R.id.btnImportData).setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - openImportDialog(); - } - }); + tableView.findViewById(R.id.btnImportData).setOnClickListener(new onClickListenerImport()); - tableView.findViewById(R.id.btnExportData).setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - openExportDialog(); - } - }); + tableView.findViewById(R.id.btnExportData).setOnClickListener(new onClickListenerExport()); - tableView.findViewById(R.id.btnDeleteAll).setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - openDeleteAllDialog(); - } - }); + tableView.findViewById(R.id.btnDeleteAll).setOnClickListener(new onClickListenerDeleteAll()); if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_XLARGE && (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_LARGE) @@ -106,8 +96,13 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { for(ScaleData scaleEntry: scaleDBEntries) { TableRow dataRow = new TableRow(tableView.getContext()); - dataRow.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - + dataRow.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + + TextView timeIdView = new TextView(tableView.getContext()); + timeIdView.setText(Long.toString(scaleEntry.id)); + timeIdView.setVisibility(View.GONE); + dataRow.addView(timeIdView); + TextView dateTextView = new TextView(tableView.getContext()); if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE || (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) { @@ -143,6 +138,19 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { muscleView.setPadding(0, 5, 5, 5); dataRow.addView(muscleView); + Button deleteButton = new Button(tableView.getContext()); + deleteButton.setText("X"); + deleteButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10); + deleteButton.setTextColor(Color.WHITE); + deleteButton.setBackground(getResources().getDrawable(R.drawable.flat_selector)); + deleteButton.setGravity(Gravity.CENTER); + deleteButton.setPadding(0, 0, 0, 0); + deleteButton.setMinimumHeight(35); + deleteButton.setHeight(35); + deleteButton.setOnClickListener(new onClickListenerDelete()); + dataRow.addView(deleteButton); + + if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_XLARGE && (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_LARGE) { @@ -154,108 +162,128 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { muscleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11); } - tableDataView.addView(dataRow, new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + tableDataView.addView(dataRow, new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } } - - public void openImportDialog() - { - AlertDialog.Builder filenameDialog = new AlertDialog.Builder(getActivity()); - filenameDialog.setTitle(getResources().getString(R.string.info_set_filename) + " /sdcard ..."); + private class onClickListenerImport implements View.OnClickListener { + @Override + public void onClick(View v) { + AlertDialog.Builder filenameDialog = new AlertDialog.Builder(getActivity()); - final EditText txtFilename = new EditText(tableView.getContext()); - txtFilename.setText("/openScale_data.csv"); - - filenameDialog.setView(txtFilename); + filenameDialog.setTitle(getResources().getString(R.string.info_set_filename) + " /sdcard ..."); - filenameDialog.setPositiveButton(getResources().getString(R.string.label_ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - boolean isError = false; - - try { - OpenScale.getInstance(tableView.getContext()).importData(Environment.getExternalStorageDirectory().getPath() + txtFilename.getText().toString()); - } catch (IOException e) { - Toast.makeText(tableView.getContext(), getResources().getString(R.string.error_importing) + " " + e.getMessage(), Toast.LENGTH_SHORT).show(); - isError = true; - } - - if (!isError) { - Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_imported) + " /sdcard" + txtFilename.getText().toString(), Toast.LENGTH_SHORT).show(); - updateOnView(OpenScale.getInstance(tableView.getContext()).getScaleDBEntries()); - } - } - }); - - filenameDialog.setNegativeButton(getResources().getString(R.string.label_cancel), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - } - }); + final EditText txtFilename = new EditText(tableView.getContext()); + txtFilename.setText("/openScale_data.csv"); + + filenameDialog.setView(txtFilename); + + filenameDialog.setPositiveButton(getResources().getString(R.string.label_ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + boolean isError = false; + + try { + OpenScale.getInstance(tableView.getContext()).importData(Environment.getExternalStorageDirectory().getPath() + txtFilename.getText().toString()); + } catch (IOException e) { + Toast.makeText(tableView.getContext(), getResources().getString(R.string.error_importing) + " " + e.getMessage(), Toast.LENGTH_SHORT).show(); + isError = true; + } + + if (!isError) { + Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_imported) + " /sdcard" + txtFilename.getText().toString(), Toast.LENGTH_SHORT).show(); + updateOnView(OpenScale.getInstance(tableView.getContext()).getScaleDBEntries()); + } + } + }); + + filenameDialog.setNegativeButton(getResources().getString(R.string.label_cancel), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.dismiss(); + } + }); - filenameDialog.show(); - } - - public void openExportDialog() - { - AlertDialog.Builder filenameDialog = new AlertDialog.Builder(getActivity()); + filenameDialog.show(); + } + } - filenameDialog.setTitle(getResources().getString(R.string.info_set_filename) + " /sdcard ..."); + private class onClickListenerExport implements View.OnClickListener { + @Override + public void onClick(View v) { + AlertDialog.Builder filenameDialog = new AlertDialog.Builder(getActivity()); - final EditText txtFilename = new EditText(tableView.getContext()); - txtFilename.setText("/openScale_data.csv"); - - filenameDialog.setView(txtFilename); + filenameDialog.setTitle(getResources().getString(R.string.info_set_filename) + " /sdcard ..."); - filenameDialog.setPositiveButton(getResources().getString(R.string.label_ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - boolean isError = false; - - try { - OpenScale.getInstance(tableView.getContext()).exportData(Environment.getExternalStorageDirectory().getPath() + txtFilename.getText().toString()); - } catch (IOException e) { - Toast.makeText(tableView.getContext(), getResources().getString(R.string.error_exporting) + " " + e.getMessage(), Toast.LENGTH_SHORT).show(); - isError = true; - } - - if (!isError) { - Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_exported) + " /sdcard" + txtFilename.getText().toString(), Toast.LENGTH_SHORT).show(); - } - } - }); - - filenameDialog.setNegativeButton(getResources().getString(R.string.label_cancel), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - } - }); + final EditText txtFilename = new EditText(tableView.getContext()); + txtFilename.setText("/openScale_data.csv"); + + filenameDialog.setView(txtFilename); + + filenameDialog.setPositiveButton(getResources().getString(R.string.label_ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + boolean isError = false; + + try { + OpenScale.getInstance(tableView.getContext()).exportData(Environment.getExternalStorageDirectory().getPath() + txtFilename.getText().toString()); + } catch (IOException e) { + Toast.makeText(tableView.getContext(), getResources().getString(R.string.error_exporting) + " " + e.getMessage(), Toast.LENGTH_SHORT).show(); + isError = true; + } + + if (!isError) { + Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_exported) + " /sdcard" + txtFilename.getText().toString(), Toast.LENGTH_SHORT).show(); + } + } + }); + + filenameDialog.setNegativeButton(getResources().getString(R.string.label_cancel), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.dismiss(); + } + }); - filenameDialog.show(); - } - - public void openDeleteAllDialog() - { - AlertDialog.Builder deleteAllDialog = new AlertDialog.Builder(getActivity()); - - deleteAllDialog.setMessage(getResources().getString(R.string.question_really_delete_all)); - - deleteAllDialog.setPositiveButton(getResources().getString(R.string.label_yes), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - OpenScale.getInstance(tableView.getContext()).deleteAllDBEntries(); - - Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_deleted), Toast.LENGTH_SHORT).show(); - updateOnView(OpenScale.getInstance(tableView.getContext()).getScaleDBEntries()); - } - }); - - deleteAllDialog.setNegativeButton(getResources().getString(R.string.label_no), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - } - }); + filenameDialog.show(); + } + } - deleteAllDialog.show(); - } + private class onClickListenerDeleteAll implements View.OnClickListener { + @Override + public void onClick(View v) { + AlertDialog.Builder deleteAllDialog = new AlertDialog.Builder(getActivity()); + + deleteAllDialog.setMessage(getResources().getString(R.string.question_really_delete_all)); + + deleteAllDialog.setPositiveButton(getResources().getString(R.string.label_yes), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + OpenScale.getInstance(tableView.getContext()).deleteAllDBEntries(); + + Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_all_deleted), Toast.LENGTH_SHORT).show(); + updateOnView(OpenScale.getInstance(tableView.getContext()).getScaleDBEntries()); + } + }); + + deleteAllDialog.setNegativeButton(getResources().getString(R.string.label_no), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.dismiss(); + } + }); + + deleteAllDialog.show(); + } + } + + private class onClickListenerDelete implements View.OnClickListener { + @Override + public void onClick(View v) { + TableRow dataRow = (TableRow)v.getParent(); + TextView idTextView = (TextView) dataRow.getChildAt(0); + long id = Long.parseLong(idTextView.getText().toString()); + + OpenScale.getInstance(tableView.getContext()).deleteScaleData(id); + + Toast.makeText(tableView.getContext(), getResources().getString(R.string.info_data_deleted), Toast.LENGTH_SHORT).show(); + updateOnView(OpenScale.getInstance(tableView.getContext()).getScaleDBEntries()); + } + } } diff --git a/android_app/app/src/main/res/drawable-hdpi/ic_launcher.png b/android_app/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..78933cb7b64e41d91edbd0711495075e7429688f GIT binary patch literal 2039 zcmVp1wMXQxc#^4*1(Nv7as;N?1i>RTY2_~jg#*nH5 zL5n0vk`bd3j7_EZ!0MPu&BQtx2h_2_j?-wx>~y9zsfn4UV*AHgf-X__-hJF`d%v0Q z4<38&@AvKRob#REo&_XGkRU;V1PKx(NRSX+Pyl2Ac0vP{p~-o#JrCFPxMpf ztp*SeQc>ZB!C=s4)bH&TJJC?+?ePtnX8m9TfCPlOk|^uK>R&`8=O`8~I%W5v@+ozDu909Ip8QRAEy`rBAZucMbeKY~}v?>6^CY>j$_A(|hCemR11k z0jvd3MJv_o)J}Jc>5&z^>A&3lvA270DBL2Yu5CUFz>Y9YHOeq;QF%B5%YF6zFZ2(W z{ZYXFcE+QfKkbD4whw&0Q3N?0CEA8YMl8EV{2N^c@O$-hpmeC{OL2fhMNX} z35P&*>YAoELYhVgeYfpZn=i{)ZU=w`0MY=kAX_j6fOb67)~U|$lmbu=|IVL)8NlR( ziL+bscJ+N0E|ECzlyv~Oa0n#N+;re%DB@TiTX`Np9f0uwv>095v@U1dtT;921)vW2 z8wIjGCo{IxAG=ykTn&dnrqUFe0mHva)YHb%c$JOvt? zJ5ERdd9R*65=?{3$hSDNFW*jqf)7C@3`iYWO3^F0$2M7gF*#zwVb#LpeSHm-k=go%2o)e9{*OJj^O7wt<&ieO>>sl46k_w z`~PxFotC>3WXlg6hqcUKwN?wf0?|q3b6Vx4JQ2-2CTYAn46-eVOs78oh zNam>7-o@vk-tNI6|M9^AfMW9|6(^V1HK|nk;YIdqD9v_|mXMvR=uRVh_lI)w_vO`Nt7!EG4#ggoQLeJ6OWKOOyF0(b#{5dfvp zn9OXNYl>2-wBzm_gNpy&oTZ}#KIpq`n7Z&o04s3!)S@&tN4`4MITs^4TAX#k>dit0 zGR#=qiV)4BBB$lVc|H$ywZ3-)z_b1&SO7Y|SbC5hjrCKj^As%(e0@sgul@>PBgoX! z-SPh{NadITB>I2mEZ?u(Bvc^lqUtV$a%eT1&6;nT0{5L_2Yt7*w;sEe-E`<&R^#Em z`|{=9kGws;p+JGN8xMV))p+Ra17F{CxZl%xQSkXJhWj6NoV;r3-y{EHJIM z{X>7H3UkxiEYBpdlZYfUHyyYL;`HN$=tISSr(~|!Nko#lZSVU46hmNNh%!uFSRr;2 zk))^V;ukWtx)cK4G&N>^)$?K}5oszdDa#O?;~xb&xuX8pVkZ!3YIDXv4S{Z2=6JeQ zuuF{-W>;xiBOWB&e08)eqq;&7<6WoxB z6((2I_X5ZOUpK8Zn;nHczFT4^5NVEmw(T@XLyn)DR%N&+h#h=1nEBFgJ_0ZfeBE?{ z_u)sx4n7*pdF8!p049THZ(2|AWtmq|BX-cyq_@X6 zq%c?)A;{h|ZF;o)XJQ8(Rdx^FQY4rbUZe>fZV|Jl0escy!YR0Xo`a0v0XJq_Xy zQb9_w1Z2gJMNS8)m^_g727@quv5p2gt0+MnXRML|nHf?0lCJ~_5+q2FAVESb;=k|V Vd!GS7(Fgzl002ovPDHLkV1ihN;kf_+ literal 0 HcmV?d00001 diff --git a/android_app/app/src/main/res/drawable-mdpi/ic_launcher.png b/android_app/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..7245ee344775482d733ff2b8db793c5a827a08ef GIT binary patch literal 1265 zcmVM^FhtZ_0BOP<;drINhiJ5N=&blk|~o|9vfuI?}XaCHs;?m7P5-#24KxwQ0I0K%x% z6ZXt>?};(SlY35%P1^hi1B$yI91tk94FDbmP{b$5$4GZ>(}MDCAEx(y{b#fWQajEC zghHVm04FK~nujXt7*F!rC%=-eJC6cb4Zr|EDArp|2{|j)UAuci0D6(uRF>4x^?9@= zNJo|rKwLEXIp)oK4=@StXnE(VK(1~AU_(gKsZ=VdM5)UFzz>Pb6AFb3jlPEC(JiA# z_8`h-#7%zw$a{2w(_TOKn?Rv{0f0fhZ0$xtqRxStkD42LQ`CjNS^#p0#RjV8mD5ZO z=u2z50Z5}U5a)dL{Smsr30e2_14stIAxSckAP6mHS*sL9iQ?0jEEN!h3jhg#!%tA% z<~sP~BXhIpgVC{`|8Tb|N7crm4Q z@CtxCLdNiQ#Z}Er4A>eD3sHl4z}&-u?jXPUqNr>Kgz_j19}6*QsxO8n`~rTDSjOqpz`h`v1`J{PHyyd8jqi2-i%&SM|2EjXNpvS;2xF!5;-=WIWFiEY8*G*>sD2B4%>Pf?U8 z{m55W*%lm5yZ_A#U{Z~lRADyAxEjlx8Ch(LosEpEu{^6_CEH?Wqo;3lf=7~hv<6fK zB|f&rMxxkYDF$6N))iN7VOwY@2L@-PT#?bX#J=O`koOkI2T$MVgt_X)kK#!A zDlqKGfZ+RvMr^hh$+MT&D{@x&* zdvKK18ODFR$zGD(WH)4!O-Oc=-OWPCjqC;x5GSCKRx1RffKJCtBOAd{kP(4SLXn_E zVNgWDf|Q_9VGIlsFdZ*bVj0F31=~7GFJO%wgHmVg%~A!mf1Hg(%tqMnY?dVFnR)&o znVj#O^PJmr-tT(>1qB5K1qB5K1qB5K1qB5K1qFox4c#E-MGHM(uw-OpS#mvPmYflz z2NR81?jj%sNCFI8L}KXdcDvnq-5pE)t9EsiZ$J7;Mf=IG2OalzeNnuz$Y1* zUs?m$xCn&MTT3TYj#~f9;kb8D|B7)s=jJ6FO{uAV#Ej6#rSt7$uACldJ^qilcSxLA zu)O6pqs3ARB-76`L1%Rr6qP=8xHI0J5O3z(wDc*!3z+&-ghcO>&8_{}(BSUQGesLa z{^eh}{}z0q z^K^fT;9aum08ob54`MzG5^`#nt&L@aO1B+8l|6I8A5BizZs0+n4wwoA0YBgda>C35 zMgSGS4}jZ}eZ`OY8k+wcZ0q{6UuMD14y#3ShW6?Be7^maBtUFu6e6I zFgmh#1IvLLU^I{gSO6oCXwCDFa@NfIDPTvey@}!9SpX+c0?f9RS8gs^|H_H}5F!1_ zS&ssqa9v^sohj4h3%=0#nd}CXJ@fYG>6JA{fX9FzhdVJX+_61JmCk-iRdw;E1MdMN z0W060_WJPOIDm3PiY=6P=bGQddN$gtMbQp^t_b5X(=u8|@9ca2dvMnd6<)L(j!Zgu=BizK7VS?0wW*GZM0| zyQ5xKr2{*UowgQ@JAml?u|TS|bV6m`{54z5Hk%hQoqL@Hh!L)j^!t>;zy$Z)RX+!Y zA!b4bg)vzfu-$E=q;}BCf!R&N; zJd2;$V;eiAj_A+U33>C^wm7c5p%HOvN=9@_N}}0(nQvM1A=v^1_n!FDleND%YFUm zmOp$dTZGiIiT8z{8?%#;X++bm*R+q8uCGiv-WP#e5S`t#lXc+^Glv`Uee0N8wkdrlQ{x4(;V4raH!-yFdXQ$}uqYtD*|!QGwz?XB$M4ITeB*c{ITv-$3M{M=_G8m-on(rrgRk|ls| z`P07#DiNVe=>kYGVc9n>dKYnv*}XjIO}V)RW~aORPQAA!NoUFRl=Zd$1a=-fol-XO z*T6!=<=i(X5r@N(Vk@0gVajy*5VNk^KVhgH@b z1a2g3*)16vStD2Pebu}8iB`m>+1nLFf_q-mlYNz&b=@6D5jUsf5tnk^W$1=Yyz2Ur zEr&XDY8$p9PF>xx+!R-+@hMpXgw5DAVstB-=&D`zh}KHl##Fro{D`wI*MK-KjskKc z2w?IzZtsXxrg!P)kMsu9lfX5-G+q}LqyTYQHoS)bNzUrJ2V@BlXgz+)V9&S(;XR}a zV92|3%~q|IO!k)SM%>$55yv$%!ic3K3{+D1=RKL~S-R<$y_HwIVgG-Oj;uCd4&Xy< zfIa`#6#iKn;?$KIex?yfaaPZ{UzPwB?I*uZ${(>1F_5H3$Bh2Q9j|JwVE)~Y{3)|K z)a;xQTA4MY?!IqW9a{0NfA^qsMrft4q4{8h(SI^?dgy?&dd`#1>beIam625)T5;|( zoHIfz3m@7eHMU_JTlF9@iVK(vA8vm`W@QH>(<^H>AmS8K-LMWwmf?a2JDt^`XMj@r z_8=E7fGN}Ei*){0Jj>kLW$lRgbdpp7lD#9x#Jh0=f$lrkyoR_4?0FQ{E`WV(RZYAb zHxTG=-0==D8Od%~dMI+Rvhd;dzaoy=X)*kN+HiWyE zCV(Mt{v%JvyKw`B7Ej3{z=cFNEX4&66{d~3;vqy#Tbdg-7d`s&Tk&q#K%t{*_9ny& z0aDzsa={l!XZ4(C`TmI9`3qnio?qA>ucHqZxy-<>FoxZ5&lk?L3E-%@p)THy8b~Z!|MCaG50T`Cl?%Q=hTU*A(ZBcfEhM_? zRy-c>Mhz&ob)7L~x^G9)i@Juq1?yVk-lzdai?8HfB)MVbf}>zKHY~*rt5|RplocCR zE;vet-LU4^u!;poNm;RB6$_4%vSPz3791sI#fDWZI7-Tj4J#KMC1u5iRV+A4%8CuE zSg-~rxkfBRqZ?K(SOaCaVda7~P^%kOE?6VAzA3F-utsWi!&1Hr9?CrDyWtBLz-)7R zWPBMvRGD-0l6Fl30M^2_FTNS?h743XCf961qhO%*_$iYkdm$RL zrzBc^WtXds_`;cY*Xq|1fq6~e4C??}Zf(QncsFPuv25FsPmNAjJtA|8=9jY!Mr-=0 zg5@om6EzJ523n7wN*i0X8F3TpL_$zr2P7G6wxF+JYs7Q`iYLD=-*NOa`}nK2B9@+f zBqsFM0~VvvSnRA0t(To?YQVFt>x{2{>)XkBBku>UMtmtBDdVFi5t0CRqRlonZPK)+ z+)!hC!OvQL=WpEcj(_EjcZV81i#8m}nz>+4vZuHan1#rDnoSH-*>`6*u^|#@k49vR ztwOAMLy1!nS$;1?q*=~Egdfi*(V%AN!VfYdvYyxwNs5LVZHQBjiM})a#uV}XZ>25< rDkvx@C@3f>C@3f>C@3f>3>>3kBkK0uWMo3 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 F{{Z((MkN3M diff --git a/android_app/app/src/main/res/layout/activity_newentry.xml b/android_app/app/src/main/res/layout/activity_newentry.xml index 7f90084c..bbdb8f57 100644 --- a/android_app/app/src/main/res/layout/activity_newentry.xml +++ b/android_app/app/src/main/res/layout/activity_newentry.xml @@ -161,6 +161,18 @@ +