diff --git a/android_app/app/src/main/AndroidManifest.xml b/android_app/app/src/main/AndroidManifest.xml index d0903303..4ea566eb 100644 --- a/android_app/app/src/main/AndroidManifest.xml +++ b/android_app/app/src/main/AndroidManifest.xml @@ -24,6 +24,7 @@ + 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 b237d1b5..7ae871c5 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 @@ -66,7 +66,7 @@ public class OpenScale { return instance; } - public void addScaleUser(String name, String birthday, int body_height, int scale_unit) + public void addScaleUser(String name, String birthday, int body_height, int scale_unit, int gender, double goal_weight, String goal_date) { ScaleUser scaleUser = new ScaleUser(); @@ -75,6 +75,9 @@ public class OpenScale { scaleUser.birthday = new SimpleDateFormat("dd.MM.yyyy").parse(birthday); scaleUser.body_height = body_height; scaleUser.scale_unit = scale_unit; + scaleUser.gender = gender; + scaleUser.goal_weight = goal_weight; + scaleUser.goal_date = new SimpleDateFormat("dd.MM.yyyy").parse(goal_date); } catch (ParseException e) { Log.e("OpenScale", "Can't parse date time string while adding to the database"); @@ -120,7 +123,7 @@ public class OpenScale { scaleUserDB.deleteEntry(id); } - public void updateScaleUser(int id, String name, String birthday, int body_height, int scale_unit) + public void updateScaleUser(int id, String name, String birthday, int body_height, int scale_unit, int gender, double goal_weight, String goal_date) { ScaleUser scaleUser = new ScaleUser(); @@ -130,6 +133,9 @@ public class OpenScale { scaleUser.birthday = new SimpleDateFormat("dd.MM.yyyy").parse(birthday); scaleUser.body_height = body_height; scaleUser.scale_unit = scale_unit; + scaleUser.gender = gender; + scaleUser.goal_weight = goal_weight; + scaleUser.goal_date = new SimpleDateFormat("dd.MM.yyyy").parse(goal_date); } catch (ParseException e) { Log.e("OpenScale", "Can't parse date time string while adding to the database"); } @@ -137,10 +143,17 @@ public class OpenScale { scaleUserDB.updateScaleUser(scaleUser); } + public ArrayList getScaleDataList() { return scaleDataList; } + + public ScaleData getScaleData(long id) + { + return scaleDB.getDataEntry(id); + } + public void addScaleData(int user_id, String date_time, float weight, float fat, float water, float muscle) { ScaleData scaleData = new ScaleData(); @@ -161,6 +174,19 @@ public class OpenScale { updateScaleData(); } + public void updateScaleData(long id, float weight, float fat, float water, float muscle) { + ScaleData scaleData = new ScaleData(); + + scaleData.weight = weight; + scaleData.fat = fat; + scaleData.water = water; + scaleData.muscle = muscle; + + scaleDB.updateEntry(id, scaleData); + + updateScaleData(); + } + public void deleteScaleData(long id) { scaleDB.deleteEntry(id); 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 6de798a3..e1d4b4ff 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 @@ -112,6 +112,68 @@ public class ScaleDatabase extends SQLiteOpenHelper { return true; } + public void updateEntry(long id, ScaleData scaleData) { + SQLiteDatabase db = getWritableDatabase(); + + ContentValues values = new ContentValues(); + 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); + + db.update(TABLE_NAME, values, COLUMN_NAME_ID + "=" + id, null); + } + + public ScaleData getDataEntry(long id) + { + SQLiteDatabase db = getReadableDatabase(); + ScaleData scaleData = new ScaleData(); + + String[] projection = { + COLUMN_NAME_ID, + COLUMN_NAME_USER_ID, + COLUMN_NAME_DATE_TIME, + COLUMN_NAME_WEIGHT, + COLUMN_NAME_FAT, + COLUMN_NAME_WATER, + COLUMN_NAME_MUSCLE + }; + + Cursor cursorScaleDB = db.query( + TABLE_NAME, // The table to query + projection, // The columns to return + COLUMN_NAME_ID + "=?", // The columns for the WHERE clause + new String[] {Long.toString(id)}, // The values for the WHERE clause + null, // don't group the rows + null, // don't filter by row groups + null // The sort order + ); + + try { + cursorScaleDB.moveToFirst(); + + scaleData.id = cursorScaleDB.getLong(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_ID)); + scaleData.user_id = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_USER_ID)); + String date_time = cursorScaleDB.getString(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_DATE_TIME)); + scaleData.weight = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_WEIGHT)); + scaleData.fat = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_FAT)); + scaleData.water = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_WATER)); + scaleData.muscle = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_MUSCLE)); + + scaleData.date_time = formatDateTime.parse(date_time); + + cursorScaleDB.moveToNext(); + + } catch (ParseException ex) { + Log.e("ScaleDatabase", "Can't parse the date time string: " + ex.getMessage()); + } + catch ( IllegalArgumentException ex) { + Log.e("ScaleDatabase", "Illegal argument while reading from scale database: " + ex.getMessage()); + } + + return scaleData; + } + public void deleteEntry(long id) { SQLiteDatabase db = getWritableDatabase(); diff --git a/android_app/app/src/main/java/com/health/openscale/core/ScaleUser.java b/android_app/app/src/main/java/com/health/openscale/core/ScaleUser.java index 41f5dc4b..e6662c60 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/ScaleUser.java +++ b/android_app/app/src/main/java/com/health/openscale/core/ScaleUser.java @@ -26,10 +26,25 @@ public class ScaleUser { public Date birthday; public int body_height; public int scale_unit; - + public int gender; + public double goal_weight; + public Date goal_date; + + public boolean isMale() + { + if (gender == 0) + return true; + + return false; + } + + public double getBMI(double weight) { + return weight / ((body_height / 100.0)*(body_height / 100.0)); + } + @Override public String toString() { - return "ID : " + id + " NAME: " + user_name + " BIRTHDAY: " + birthday.toString() + " BODY_HEIGHT: " + body_height + " SCALE_UNIT: " + UNIT_STRING[scale_unit]; + return "ID : " + id + " NAME: " + user_name + " BIRTHDAY: " + birthday.toString() + " BODY_HEIGHT: " + body_height + " SCALE_UNIT: " + UNIT_STRING[scale_unit] + " GENDER " + gender + " GOAL WEIGHT " + goal_weight + " GOAL DATE " + goal_date.toString(); } } diff --git a/android_app/app/src/main/java/com/health/openscale/core/ScaleUserDatabase.java b/android_app/app/src/main/java/com/health/openscale/core/ScaleUserDatabase.java index 41b11d5e..ca063b7e 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/ScaleUserDatabase.java +++ b/android_app/app/src/main/java/com/health/openscale/core/ScaleUserDatabase.java @@ -30,7 +30,7 @@ import java.util.ArrayList; import java.util.Locale; public class ScaleUserDatabase extends SQLiteOpenHelper { - private static final int DATABASE_VERSION = 1; + private static final int DATABASE_VERSION = 2; private static final String DATABASE_NAME = "openScaleUserDatabase.db"; private static final String TABLE_NAME = "scaleuserdata"; @@ -39,6 +39,9 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { private static final String COLUMN_NAME_BIRTHDAY = "birthday"; private static final String COLUMN_NAME_BODY_HEIGHT = "body_height"; private static final String COLUMN_NAME_SCALE_UNIT = "scale_unit"; + private static final String COLUMN_NAME_GENDER = "gender"; + private static final String COLUMN_NAME_GOAL_WEIGHT = "goal_weight"; + private static final String COLUMN_NAME_GOAL_DATE = "goal_date"; private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + TABLE_NAME + " (" + @@ -46,7 +49,10 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { COLUMN_NAME_USER_NAME + " TEXT," + COLUMN_NAME_BIRTHDAY + " TEXT," + COLUMN_NAME_BODY_HEIGHT + " INTEGER," + - COLUMN_NAME_SCALE_UNIT + " INTEGER" + + COLUMN_NAME_SCALE_UNIT + " INTEGER," + + COLUMN_NAME_GENDER + " INTEGER," + + COLUMN_NAME_GOAL_WEIGHT + " REAL," + + COLUMN_NAME_GOAL_DATE + " TEXT" + ")"; private static final String SQL_DELETE_ENTRIES = @@ -65,8 +71,11 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - db.execSQL(SQL_DELETE_ENTRIES); - onCreate(db); + if (oldVersion == 1 && newVersion == 2) { + db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_GENDER + " INTEGER DEFAULT 0"); + db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_GOAL_WEIGHT + " REAL DEFAULT 0"); + db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_GOAL_DATE + " TEXT DEFAULT '2014-01-01 00:00'"); + } } public void clearDatabase() { @@ -83,6 +92,9 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { values.put(COLUMN_NAME_BIRTHDAY, formatDateTime.format(scaleUser.birthday)); values.put(COLUMN_NAME_BODY_HEIGHT, scaleUser.body_height); values.put(COLUMN_NAME_SCALE_UNIT, scaleUser.scale_unit); + values.put(COLUMN_NAME_GENDER, scaleUser.gender); + values.put(COLUMN_NAME_GOAL_WEIGHT, scaleUser.goal_weight); + values.put(COLUMN_NAME_GOAL_DATE, formatDateTime.format(scaleUser.goal_date)); try { @@ -112,6 +124,9 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { values.put(COLUMN_NAME_BIRTHDAY, formatDateTime.format(scaleUser.birthday)); values.put(COLUMN_NAME_BODY_HEIGHT, scaleUser.body_height); values.put(COLUMN_NAME_SCALE_UNIT, scaleUser.scale_unit); + values.put(COLUMN_NAME_GENDER, scaleUser.gender); + values.put(COLUMN_NAME_GOAL_WEIGHT, scaleUser.goal_weight); + values.put(COLUMN_NAME_GOAL_DATE, formatDateTime.format(scaleUser.goal_date)); db.update(TABLE_NAME, values, COLUMN_NAME_ID + "=" + scaleUser.id, null); } @@ -126,7 +141,10 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { COLUMN_NAME_USER_NAME, COLUMN_NAME_BIRTHDAY, COLUMN_NAME_BODY_HEIGHT, - COLUMN_NAME_SCALE_UNIT + COLUMN_NAME_SCALE_UNIT, + COLUMN_NAME_GENDER, + COLUMN_NAME_GOAL_WEIGHT, + COLUMN_NAME_GOAL_DATE }; Cursor cursorScaleDB = db.query( @@ -147,8 +165,12 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { String birthday = cursorScaleDB.getString(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_BIRTHDAY)); scaleUser.body_height = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_BODY_HEIGHT)); scaleUser.scale_unit = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_SCALE_UNIT)); + scaleUser.gender = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_GENDER)); + scaleUser.goal_weight = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_GOAL_WEIGHT)); + String goal_date = cursorScaleDB.getString(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_GOAL_DATE)); scaleUser.birthday = formatDateTime.parse(birthday); + scaleUser.goal_date = formatDateTime.parse(goal_date); cursorScaleDB.moveToNext(); @@ -171,7 +193,10 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { COLUMN_NAME_USER_NAME, COLUMN_NAME_BIRTHDAY, COLUMN_NAME_BODY_HEIGHT, - COLUMN_NAME_SCALE_UNIT + COLUMN_NAME_SCALE_UNIT, + COLUMN_NAME_GENDER, + COLUMN_NAME_GOAL_WEIGHT, + COLUMN_NAME_GOAL_DATE }; String sortOrder = COLUMN_NAME_ID + " DESC"; @@ -197,8 +222,12 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { String birthday = cursorScaleDB.getString(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_BIRTHDAY)); scaleUser.body_height = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_BODY_HEIGHT)); scaleUser.scale_unit = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_SCALE_UNIT)); - - scaleUser.birthday = formatDateTime.parse(birthday); + scaleUser.gender = cursorScaleDB.getInt(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_GENDER)); + scaleUser.goal_weight = cursorScaleDB.getFloat(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_GOAL_WEIGHT)); + String goal_date = cursorScaleDB.getString(cursorScaleDB.getColumnIndexOrThrow(COLUMN_NAME_GOAL_DATE)); + + scaleUser.birthday = formatDateTime.parse(birthday); + scaleUser.goal_date = formatDateTime.parse(goal_date); scaleUserDBEntries.add(scaleUser); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/EditDataActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/EditDataActivity.java new file mode 100644 index 00000000..86ffa533 --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/gui/EditDataActivity.java @@ -0,0 +1,101 @@ +/* Copyright (C) 2014 olie.xdev +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ +package com.health.openscale.gui; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; + +import com.health.openscale.R; +import com.health.openscale.core.OpenScale; +import com.health.openscale.core.ScaleData; + +import java.text.SimpleDateFormat; + +public class EditDataActivity extends Activity { + + private EditText txtWeight; + private EditText txtFat; + private EditText txtWater; + private EditText txtMuscle; + + private Button btnOk; + private Button btnCancel; + + private long id; + + private Context context; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_editdata); + + context = this; + + txtWeight = (EditText) findViewById(R.id.txtWeight); + txtFat = (EditText) findViewById(R.id.txtFat); + txtWater = (EditText) findViewById(R.id.txtWater); + txtMuscle = (EditText) findViewById(R.id.txtMuscle); + + btnOk = (Button)findViewById(R.id.btnOk); + btnCancel = (Button)findViewById(R.id.btnCancel); + + btnOk.setOnClickListener(new onClickListenerOk()); + btnCancel.setOnClickListener(new onClickListenerCancel()); + + id = getIntent().getExtras().getLong("id"); + + OpenScale openScale = OpenScale.getInstance(context); + + ScaleData editScaleData = openScale.getScaleData(id); + + txtWeight.setText(editScaleData.weight+""); + txtFat.setText(editScaleData.fat+""); + txtWater.setText(editScaleData.water+""); + txtMuscle.setText(editScaleData.muscle+""); + + setTitle(getResources().getString(R.string.title_edit_data_entry) + ": " + new SimpleDateFormat("dd. MMM yyyy (EE) HH:mm").format(editScaleData.date_time)); + + } + + + private class onClickListenerOk implements View.OnClickListener { + @Override + public void onClick(View v) { + float weight = Float.valueOf(txtWeight.getText().toString()); + float fat = Float.valueOf(txtFat.getText().toString()); + float water = Float.valueOf(txtWater.getText().toString()); + float muscle = Float.valueOf(txtMuscle.getText().toString()); + + OpenScale openScale = OpenScale.getInstance(context); + + openScale.updateScaleData(id, weight, fat, water, muscle); + + finish(); + } + } + + private class onClickListenerCancel implements View.OnClickListener { + @Override + public void onClick(View v) { + finish(); + } + } +} diff --git a/android_app/app/src/main/java/com/health/openscale/gui/OverviewFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/OverviewFragment.java index 95c6aff0..da1d9f59 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/OverviewFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/OverviewFragment.java @@ -17,10 +17,14 @@ package com.health.openscale.gui; import android.app.Activity; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.app.Fragment; +import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -34,47 +38,114 @@ import com.health.openscale.core.ScaleUser; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; +import java.util.concurrent.TimeUnit; import lecho.lib.hellocharts.model.ArcValue; +import lecho.lib.hellocharts.model.Axis; +import lecho.lib.hellocharts.model.AxisValue; +import lecho.lib.hellocharts.model.Line; +import lecho.lib.hellocharts.model.LineChartData; import lecho.lib.hellocharts.model.PieChartData; +import lecho.lib.hellocharts.model.PointValue; import lecho.lib.hellocharts.model.SimpleValueFormatter; import lecho.lib.hellocharts.util.Utils; +import lecho.lib.hellocharts.view.LineChartView; import lecho.lib.hellocharts.view.PieChartView; public class OverviewFragment extends Fragment implements FragmentUpdateListener { private View overviewView; - private TextView txtOverviewTitle; - private PieChartView pieChart; - private TextView txtAvgWeight; - private TextView txtAvgFat; - private TextView txtAvgWater; - private TextView txtAvgMuscle; + private TextView txtTitleUser; + private TextView txtTitleLastMeasurement; + private TextView txtTitleGoal; + private TextView txtTitleStatistics; + + private TextView txtWeightLast; + private TextView txtBMILast; + private TextView txtWaterLast; + private TextView txtMuscleLast; + private TextView txtFatLast; + + private TextView txtGoalWeight; + private TextView txtGoalDiff; + private TextView txtGoalDayLeft; + + private TextView txtAvgWeek; + private TextView txtAvgMonth; + + private TextView txtLabelWeight; + private TextView txtLabelBMI; + private TextView txtLabelFat; + private TextView txtLabelMuscle; + private TextView txtLabelWater; + + private TextView txtLabelGoalWeight; + private TextView txtLabelGoalDiff; + private TextView txtLabelDayLeft; + + private TextView txtLabelAvgWeek; + private TextView txtLabelAvgMonth; + + private PieChartView pieChartLast; + private LineChartView lineChartLast; + + private SharedPreferences prefs; private ScaleData lastScaleData; + private ScaleUser currentScaleUser; - @Override + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { overviewView = inflater.inflate(R.layout.fragment_overview, container, false); - txtOverviewTitle = (TextView) overviewView.findViewById(R.id.txtOverviewTitle); - pieChart = (PieChartView) overviewView.findViewById(R.id.pieChart); - txtAvgWeight = (TextView) overviewView.findViewById(R.id.txtAvgWeight); - txtAvgFat = (TextView) overviewView.findViewById(R.id.txtAvgFat); - txtAvgWater = (TextView) overviewView.findViewById(R.id.txtAvgWater); - txtAvgMuscle = (TextView) overviewView.findViewById(R.id.txtAvgMuscle); + txtTitleUser = (TextView) overviewView.findViewById(R.id.txtTitleUser); + txtTitleLastMeasurement = (TextView) overviewView.findViewById(R.id.txtTitleLastMeasurment); + txtTitleGoal = (TextView) overviewView.findViewById(R.id.txtTitleGoal); + txtTitleStatistics = (TextView) overviewView.findViewById(R.id.txtTitleStatistics); - pieChart.setOnValueTouchListener(new PieChartTouchListener()); - pieChart.setChartRotationEnabled(false); + txtWeightLast = (TextView) overviewView.findViewById(R.id.txtWeightLast); + txtBMILast = (TextView) overviewView.findViewById(R.id.txtBMILast); + txtWaterLast = (TextView) overviewView.findViewById(R.id.txtWaterLast); + txtMuscleLast = (TextView) overviewView.findViewById(R.id.txtMuscleLast); + txtFatLast = (TextView) overviewView.findViewById(R.id.txtFatLast); + + txtGoalWeight = (TextView) overviewView.findViewById(R.id.txtGoalWeight); + txtGoalDiff = (TextView) overviewView.findViewById(R.id.txtGoalDiff); + txtGoalDayLeft = (TextView) overviewView.findViewById(R.id.txtGoalDayLeft); + + txtAvgWeek = (TextView) overviewView.findViewById(R.id.txtAvgWeek); + txtAvgMonth = (TextView) overviewView.findViewById(R.id.txtAvgMonth); + + txtLabelWeight = (TextView) overviewView.findViewById(R.id.txtLabelWeight); + txtLabelBMI = (TextView) overviewView.findViewById(R.id.txtLabelBMI); + txtLabelFat = (TextView) overviewView.findViewById(R.id.txtLabelFat); + txtLabelMuscle = (TextView) overviewView.findViewById(R.id.txtLabelMuscle); + txtLabelWater = (TextView) overviewView.findViewById(R.id.txtLabelWater); + + txtLabelGoalWeight = (TextView) overviewView.findViewById(R.id.txtLabelGoalWeight); + txtLabelGoalDiff = (TextView) overviewView.findViewById(R.id.txtLabelGoalDiff); + txtLabelDayLeft = (TextView) overviewView.findViewById(R.id.txtLabelDayLeft); + + txtLabelAvgWeek = (TextView) overviewView.findViewById(R.id.txtLabelAvgWeek); + txtLabelAvgMonth = (TextView) overviewView.findViewById(R.id.txtLabelAvgMonth); + + pieChartLast = (PieChartView) overviewView.findViewById(R.id.pieChartLast); + lineChartLast = (LineChartView) overviewView.findViewById(R.id.lineChartLast); + + pieChartLast.setOnValueTouchListener(new PieChartLastTouchListener()); + pieChartLast.setChartRotationEnabled(false); overviewView.findViewById(R.id.btnInsertData).setOnClickListener(new View.OnClickListener() { public void onClick(View view) { btnOnClickInsertData(); } }); - + + prefs = PreferenceManager.getDefaultSharedPreferences(overviewView.getContext()); + updateOnView(OpenScale.getInstance(overviewView.getContext()).getScaleDataList()); return overviewView; @@ -83,66 +154,287 @@ public class OverviewFragment extends Fragment implements FragmentUpdateListener @Override public void updateOnView(ArrayList scaleDataList) { - ScaleUser scaleUser = OpenScale.getInstance(overviewView.getContext()).getSelectedScaleUser(); + currentScaleUser = OpenScale.getInstance(overviewView.getContext()).getSelectedScaleUser(); - txtOverviewTitle.setText(getResources().getString(R.string.label_overview_title_start) + " " + scaleUser.user_name + " " + getResources().getString(R.string.label_overview_title_end)); - - List arcValues = new ArrayList(); - - if (scaleDataList.isEmpty()) { + if (scaleDataList.isEmpty()) { lastScaleData = null; return; } lastScaleData = scaleDataList.get(0); - - arcValues.add(new ArcValue(lastScaleData.fat, Utils.COLOR_ORANGE)); - arcValues.add(new ArcValue(lastScaleData.water, Utils.COLOR_BLUE)); - arcValues.add(new ArcValue(lastScaleData.muscle, Utils.COLOR_GREEN)); - - PieChartData pieChartData = new PieChartData(arcValues); - pieChartData.setHasLabels(true); + + txtTitleUser.setText(getResources().getString(R.string.label_title_user).toUpperCase() + " " + currentScaleUser.user_name); + txtTitleLastMeasurement.setText(getResources().getString(R.string.label_title_last_measurement).toUpperCase()); + txtTitleGoal.setText(getResources().getString(R.string.label_title_goal).toUpperCase()); + txtTitleStatistics.setText(getResources().getString(R.string.label_title_statistics).toUpperCase()); + + updateLastPieChart(); + updateLastLineChart(scaleDataList); + updateLastMeasurement(); + updateGoal(scaleDataList); + updateStatistics(scaleDataList); + } + + private void updateLastMeasurement() { + txtWeightLast.setText(lastScaleData.weight + " " + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit]); + txtBMILast.setText(String.format("%.1f", currentScaleUser.getBMI(lastScaleData.weight))); + txtFatLast.setText(lastScaleData.fat + " %"); + txtWaterLast.setText(lastScaleData.water + " %"); + txtMuscleLast.setText(lastScaleData.muscle + " %"); + } + + private void updateGoal(ArrayList scaleDataList) { + txtGoalWeight.setText(currentScaleUser.goal_weight + " " + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit]); + + double weight_diff = currentScaleUser.goal_weight - lastScaleData.weight; + txtGoalDiff.setText(weight_diff + " " + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit]); + + Calendar goalDate = Calendar.getInstance(); + Calendar curDate = Calendar.getInstance(); + goalDate.setTime(currentScaleUser.goal_date); + + long days = daysBetween(curDate, goalDate); + txtGoalDayLeft.setText(days + " " + getResources().getString(R.string.label_days)); + + txtLabelGoalWeight.setText(Html.fromHtml(getResources().getString(R.string.label_weight_goal) + "
BMI " + String.format("%.1f", currentScaleUser.getBMI(currentScaleUser.goal_weight)) + " ")); + txtLabelGoalDiff.setText(Html.fromHtml(getResources().getString(R.string.label_weight_difference) + "
BMI " + String.format("%.1f", currentScaleUser.getBMI(lastScaleData.weight) - currentScaleUser.getBMI(currentScaleUser.goal_weight)) + " ")); + txtLabelDayLeft.setText(Html.fromHtml(getResources().getString(R.string.label_days_left) + "
" + getResources().getString(R.string.label_goal_date_is) + " " + new SimpleDateFormat("dd. MMM yyyy (EE)").format(currentScaleUser.goal_date) + " ")); + + if (scaleDataList.size() > 2) { + ScaleData diffScaleData = scaleDataList.get(1); + + double diffWeight = lastScaleData.weight - diffScaleData.weight; + double diffBMI = currentScaleUser.getBMI(lastScaleData.weight) - currentScaleUser.getBMI(diffScaleData.weight); + double diffFat = lastScaleData.fat - diffScaleData.fat; + double diffMuscle = lastScaleData.muscle - diffScaleData.muscle; + double diffWater = lastScaleData.water - diffScaleData.water; + + if (diffWeight > 0.0) + txtLabelWeight.setText(Html.fromHtml(getResources().getString(R.string.label_weight) + "
" + String.format("%.1f ", diffWeight) + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit] + "")); + else + txtLabelWeight.setText(Html.fromHtml(getResources().getString(R.string.label_weight) + "
" + String.format("%.1f ", diffWeight) + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit] + "")); + + + if (diffBMI > 0.0) + txtLabelBMI.setText(Html.fromHtml(getResources().getString(R.string.label_bmi) + "
" + String.format("%.1f", diffBMI) + "")); + else + txtLabelBMI.setText(Html.fromHtml(getResources().getString(R.string.label_bmi) + "
" + String.format("%.1f", diffBMI) + "")); + + if (diffFat > 0.0) + txtLabelFat.setText(Html.fromHtml(getResources().getString(R.string.label_fat) + "
" + String.format("%.1f", diffFat) + "%")); + else + txtLabelFat.setText(Html.fromHtml(getResources().getString(R.string.label_fat) + "
" + String.format("%.1f", diffFat) + "%")); + + if (diffMuscle > 0.0) + txtLabelMuscle.setText(Html.fromHtml(getResources().getString(R.string.label_muscle) + "
" + String.format("%.1f", diffMuscle) + "%")); + else + txtLabelMuscle.setText(Html.fromHtml(getResources().getString(R.string.label_muscle) + "
" + String.format("%.1f", diffMuscle) + "%")); + + if (diffWater > 0.0) + txtLabelWater.setText(Html.fromHtml(getResources().getString(R.string.label_water) + "
" + String.format("%.1f", diffWater) + "%")); + else + txtLabelWater.setText(Html.fromHtml(getResources().getString(R.string.label_water) + "
" + String.format("%.1f", diffWater) + "%")); + } + } + + private void updateStatistics(ArrayList scaleDataList) { + Calendar histDate = Calendar.getInstance(); + Calendar weekPastDate = Calendar.getInstance(); + Calendar monthPastDate = Calendar.getInstance(); + + weekPastDate.setTime(lastScaleData.date_time); + weekPastDate.add(Calendar.DATE, -7); + + monthPastDate.setTime(lastScaleData.date_time); + monthPastDate.add(Calendar.DATE, -30); + + int weekSize = 0; + float weekAvgWeight = 0; + float weekAvgBMI = 0; + float weekAvgFat = 0; + float weekAvgWater = 0; + float weekAvgMuscle = 0; + + int monthSize = 0; + float monthAvgWeight = 0; + float monthAvgBMI = 0; + float monthAvgFat = 0; + float monthAvgWater = 0; + float monthAvgMuscle = 0; + + for (ScaleData scaleData : scaleDataList) + { + histDate.setTime(scaleData.date_time); + + if (weekPastDate.before(histDate)) { + weekSize++; + + weekAvgWeight += scaleData.weight; + weekAvgBMI += currentScaleUser.getBMI(scaleData.weight); + weekAvgFat += scaleData.fat; + weekAvgWater += scaleData.water; + weekAvgMuscle += scaleData.muscle; + } + + if (monthPastDate.before(histDate)) { + monthSize++; + + monthAvgWeight += scaleData.weight; + monthAvgBMI += currentScaleUser.getBMI(scaleData.weight); + monthAvgFat += scaleData.fat; + monthAvgWater += scaleData.water; + monthAvgMuscle += scaleData.muscle; + } else { + break; + } + } + + weekAvgWeight /= weekSize; + weekAvgBMI /= weekSize; + weekAvgFat /= weekSize; + weekAvgWater /= weekSize; + weekAvgMuscle /= weekSize; + + monthAvgWeight /= monthSize; + monthAvgBMI /= monthSize; + monthAvgFat /= monthSize; + monthAvgWater /= monthSize; + monthAvgMuscle /= monthSize; + + txtLabelAvgWeek.setText(Html.fromHtml(getResources().getString(R.string.label_last_week) + "
" + String.format("[Ø-"+getResources().getString(R.string.label_weight)+": %.1f" + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit] + "] [Ø-"+getResources().getString(R.string.label_bmi)+": %.1f] [Ø-"+getResources().getString(R.string.label_fat)+": %.1f%%] [Ø-"+getResources().getString(R.string.label_muscle)+": %.1f%%] [Ø-"+getResources().getString(R.string.label_water)+": %.1f%%]", weekAvgWeight, weekAvgBMI, weekAvgFat, weekAvgMuscle, weekAvgWater) + "")); + txtLabelAvgMonth.setText(Html.fromHtml(getResources().getString(R.string.label_last_month) + "
" + String.format("[Ø-"+getResources().getString(R.string.label_weight)+": %.1f" + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit] + "] [Ø-"+getResources().getString(R.string.label_bmi)+": %.1f] [Ø-"+getResources().getString(R.string.label_fat)+": %.1f%%] [Ø-"+getResources().getString(R.string.label_muscle)+": %.1f%%] [Ø-"+getResources().getString(R.string.label_water)+": %.1f%%]", monthAvgWeight, monthAvgBMI, monthAvgFat, monthAvgMuscle, monthAvgWater) + "")); + + txtAvgWeek.setText(weekSize + " " + getResources().getString(R.string.label_measures)); + txtAvgMonth.setText(monthSize + " " + getResources().getString(R.string.label_measures)); + } + + private void updateLastLineChart(ArrayList scaleDataList) { + List axisValues = new ArrayList(); + + List valuesWeight = new ArrayList(); + List valuesFat = new ArrayList(); + List valuesWater = new ArrayList(); + List valuesMuscle = new ArrayList(); + List lines = new ArrayList(); + + int max_i = 7; + + if (scaleDataList.size() < 7) { + max_i = scaleDataList.size(); + } + + Calendar histDate = Calendar.getInstance(); + Calendar lastDate = Calendar.getInstance(); + + lastDate.setTime(scaleDataList.get(0).date_time); + + for (int i=0; i arcValuesLast = new ArrayList(); + + arcValuesLast.add(new ArcValue(lastScaleData.fat, Utils.COLOR_ORANGE)); + arcValuesLast.add(new ArcValue(lastScaleData.water, Utils.COLOR_BLUE)); + arcValuesLast.add(new ArcValue(lastScaleData.muscle, Utils.COLOR_GREEN)); + + PieChartData pieChartData = new PieChartData(arcValuesLast); + pieChartData.setHasLabels(false); pieChartData.setFormatter(new SimpleValueFormatter(1, false, null, " %".toCharArray())); - pieChartData.setHasCenterCircle(true); - pieChartData.setCenterText1(Float.toString(lastScaleData.weight) + " " + ScaleUser.UNIT_STRING[scaleUser.scale_unit]); - pieChartData.setCenterText2(new SimpleDateFormat("dd. MMM yyyy (EE)").format(lastScaleData.date_time)); + pieChartData.setHasCenterCircle(true); + pieChartData.setCenterText1(Float.toString(lastScaleData.weight) + " " + ScaleUser.UNIT_STRING[currentScaleUser.scale_unit]); + pieChartData.setCenterText2(new SimpleDateFormat("dd. MMM yyyy").format(lastScaleData.date_time)); + if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE || - (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) { - pieChartData.setCenterText1FontSize(33); + (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) { + pieChartData.setCenterText1FontSize(25); pieChartData.setCenterText2FontSize(14); } else { - pieChartData.setCenterText1FontSize(12); + pieChartData.setCenterText1FontSize(10); pieChartData.setCenterText2FontSize(8); pieChartData.setValueLabelTextSize(8); } - - pieChart.setPieChartData(pieChartData); - - double avgWeight = 0; - double avgFat = 0; - double avgWater = 0; - double avgMuscle = 0; - - for (ScaleData scaleData : scaleDataList) - { - avgWeight += scaleData.weight; - avgFat += scaleData.fat; - avgWater += scaleData.water; - avgMuscle += scaleData.muscle; - } - - avgWeight = avgWeight / scaleDataList.size(); - avgFat = avgFat / scaleDataList.size(); - avgWater = avgWater / scaleDataList.size(); - avgMuscle = avgMuscle / scaleDataList.size(); - - txtAvgWeight.setText(String.format( "%.1f " + ScaleUser.UNIT_STRING[scaleUser.scale_unit], avgWeight)); - txtAvgFat.setText(String.format( "%.1f %%", avgFat)); - txtAvgWater.setText(String.format( "%.1f %%", avgWater)); - txtAvgMuscle.setText(String.format( "%.1f %%", avgMuscle)); - } + + pieChartLast.setPieChartData(pieChartData); + } + + private long daysBetween(Calendar startDate, Calendar endDate) { + long end = endDate.getTimeInMillis(); + long start = startDate.getTimeInMillis(); + return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start)); + } public void btnOnClickInsertData() { @@ -150,7 +442,7 @@ public class OverviewFragment extends Fragment implements FragmentUpdateListener startActivityForResult(intent, 1); } - private class PieChartTouchListener implements PieChartView.PieChartOnValueTouchListener + private class PieChartLastTouchListener implements PieChartView.PieChartOnValueTouchListener { @Override public void onValueTouched(int i, ArcValue arcValue) 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 738237ad..a879e819 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,6 +18,7 @@ package com.health.openscale.gui; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -154,6 +155,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { deleteButton.setOnClickListener(new onClickListenerDelete()); dataRow.addView(deleteButton); + dataRow.setOnClickListener(new onClickListenerRow()); if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_XLARGE && (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) != Configuration.SCREENLAYOUT_SIZE_LARGE) @@ -170,6 +172,20 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { } } + private class onClickListenerRow implements View.OnClickListener { + + @Override + public void onClick(View v) { + TableRow dataRow = (TableRow)v; + TextView idTextView = (TextView) dataRow.getChildAt(0); + long id = Long.parseLong(idTextView.getText().toString()); + + Intent intent = new Intent(tableView.getContext(), EditDataActivity.class); + intent.putExtra("id", id); + startActivityForResult(intent, 1); + } + } + private class onClickListenerImport implements View.OnClickListener { @Override public void onClick(View v) { diff --git a/android_app/app/src/main/java/com/health/openscale/gui/UserSettingsActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/UserSettingsActivity.java index 7671257c..9a3468cb 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/UserSettingsActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/UserSettingsActivity.java @@ -47,14 +47,18 @@ public class UserSettingsActivity extends Activity { private EditText txtUserName; private EditText txtBodyHeight; private EditText txtBirthday; + private EditText txtGoalWeight; + private EditText txtGoalDate; private RadioGroup radioScaleUnit; + private RadioGroup radioGender; private Button btnBirthdaySet; + private Button btnGoalDateSet; private Button btnOk; private Button btnCancel; private Button btnDelete; - private SimpleDateFormat birthdayFormat = new SimpleDateFormat("dd.MM.yyyy"); + private SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); private Context context; @@ -67,10 +71,14 @@ public class UserSettingsActivity extends Activity { txtUserName = (EditText) findViewById(R.id.txtUserName); txtBodyHeight = (EditText) findViewById(R.id.txtBodyHeight); radioScaleUnit = (RadioGroup) findViewById(R.id.groupScaleUnit); + radioGender = (RadioGroup) findViewById(R.id.groupGender); + txtGoalWeight = (EditText) findViewById(R.id.txtGoalWeight); txtBirthday = (EditText) findViewById(R.id.txtBirthday); + txtGoalDate = (EditText) findViewById(R.id.txtGoalDate); btnBirthdaySet = (Button) findViewById(R.id.btnDateSet); + btnGoalDateSet = (Button) findViewById(R.id.btnGoalDateSet); btnDelete = (Button) findViewById(R.id.btnDelete); btnOk = (Button)findViewById(R.id.btnOk); btnCancel = (Button)findViewById(R.id.btnCancel); @@ -79,8 +87,11 @@ public class UserSettingsActivity extends Activity { btnCancel.setOnClickListener(new onClickListenerCancel()); btnDelete.setOnClickListener(new onClickListenerDelete()); btnBirthdaySet.setOnClickListener(new onClickListenerBirthdaySet()); + btnGoalDateSet.setOnClickListener(new onClickListenerGoalDateSet()); - txtBirthday.setText(birthdayFormat.format(new Date())); + txtBirthday.setText(dateFormat.format(new Date())); + + txtGoalDate.setText(dateFormat.format(new Date())); if (getIntent().getExtras().getInt("mode") == EDIT_USER_REQUEST) { @@ -102,9 +113,11 @@ public class UserSettingsActivity extends Activity { txtUserName.setText(scaleUser.user_name); txtBodyHeight.setText(Integer.toString(scaleUser.body_height)); - txtBirthday.setText(birthdayFormat.format(scaleUser.birthday)); + txtBirthday.setText(dateFormat.format(scaleUser.birthday)); + txtGoalDate.setText(dateFormat.format(scaleUser.goal_date)); + txtGoalWeight.setText(scaleUser.goal_weight+""); - switch (scaleUser.scale_unit) + switch (scaleUser.scale_unit) { case 0: radioScaleUnit.check(R.id.btnRadioKG); @@ -116,6 +129,16 @@ public class UserSettingsActivity extends Activity { radioScaleUnit.check(R.id.btnRadioST); break; } + + switch (scaleUser.gender) + { + case 0: + radioGender.check(R.id.btnRadioMale); + break; + case 1: + radioGender.check(R.id.btnRadioWoman); + break; + } } private boolean validateInput() @@ -144,6 +167,13 @@ public class UserSettingsActivity extends Activity { } }; + private DatePickerDialog.OnDateSetListener goalDatePickerListener = new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int selectedYear, int selectedMonth, int selectedDay) { + txtGoalDate.setText(String.format("%02d.%02d.%04d", selectedDay, selectedMonth + 1, selectedYear)); + } + }; + private class onClickListenerDelete implements View.OnClickListener { @Override public void onClick(View v) { @@ -197,6 +227,8 @@ public class UserSettingsActivity extends Activity { String name = txtUserName.getText().toString(); int body_height = Integer.valueOf(txtBodyHeight.getText().toString()); int checkedRadioButtonId = radioScaleUnit.getCheckedRadioButtonId(); + int checkedGenderId = radioGender.getCheckedRadioButtonId(); + double goal_weight = Double.valueOf(txtGoalWeight.getText().toString()); int scale_unit = -1; @@ -212,17 +244,29 @@ public class UserSettingsActivity extends Activity { break; } + int gender = -1; + + switch (checkedGenderId) { + case R.id.btnRadioMale: + gender = 0; + break; + case R.id.btnRadioWoman: + gender = 1; + break; + } + String date = txtBirthday.getText().toString(); + String goal_date = txtGoalDate.getText().toString(); int id = -1; if (getIntent().getExtras().getInt("mode") == EDIT_USER_REQUEST) { id = getIntent().getExtras().getInt("id"); - openScale.updateScaleUser(id, name, date, body_height, scale_unit); + openScale.updateScaleUser(id, name, date, body_height, scale_unit, gender, goal_weight, goal_date); } else { - openScale.addScaleUser(name, date, body_height, scale_unit); + openScale.addScaleUser(name, date, body_height, scale_unit, gender, goal_weight, goal_date); id = openScale.getScaleUserList().get(0).id; } @@ -247,6 +291,16 @@ public class UserSettingsActivity extends Activity { } } + + private class onClickListenerGoalDateSet implements View.OnClickListener { + @Override + public void onClick(View v) { + Calendar cal = Calendar.getInstance(); + DatePickerDialog datePicker = new DatePickerDialog(context, goalDatePickerListener, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); + datePicker.show(); + } + } + private class onClickListenerCancel implements View.OnClickListener { @Override public void onClick(View v) { diff --git a/android_app/app/src/main/res/drawable/bmi.png b/android_app/app/src/main/res/drawable/bmi.png new file mode 100644 index 00000000..484ab7c3 Binary files /dev/null and b/android_app/app/src/main/res/drawable/bmi.png differ diff --git a/android_app/app/src/main/res/drawable/lastmonth.png b/android_app/app/src/main/res/drawable/lastmonth.png new file mode 100644 index 00000000..2a8eb7a1 Binary files /dev/null and b/android_app/app/src/main/res/drawable/lastmonth.png differ diff --git a/android_app/app/src/main/res/drawable/lastweek.png b/android_app/app/src/main/res/drawable/lastweek.png new file mode 100644 index 00000000..f76cdbfe Binary files /dev/null and b/android_app/app/src/main/res/drawable/lastweek.png differ diff --git a/android_app/app/src/main/res/drawable/muscle.png b/android_app/app/src/main/res/drawable/muscle.png new file mode 100644 index 00000000..915c57dc Binary files /dev/null and b/android_app/app/src/main/res/drawable/muscle.png differ diff --git a/android_app/app/src/main/res/drawable/water.png b/android_app/app/src/main/res/drawable/water.png new file mode 100644 index 00000000..0543a9ea Binary files /dev/null and b/android_app/app/src/main/res/drawable/water.png differ diff --git a/android_app/app/src/main/res/layout/activity_usersettings.xml b/android_app/app/src/main/res/layout/activity_usersettings.xml index 96b97391..7eefe335 100644 --- a/android_app/app/src/main/res/layout/activity_usersettings.xml +++ b/android_app/app/src/main/res/layout/activity_usersettings.xml @@ -64,6 +64,41 @@ android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@string/label_gender" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + +