diff --git a/app/build.gradle b/app/build.gradle
index 7eb0a1e..0ab7788 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -33,6 +33,7 @@ android {
dependencies {
+ implementation 'com.jjoe64:graphview:4.2.2'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2ce6c0..3d63851 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,9 +13,10 @@
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ android:exported="false"
+ android:screenOrientation="landscape"/>
"+(0.109*mos.bras + 0.093*mos.cuisse + 0.276*mos.avantBras + 0.078*mos.abdomen - 0.056*mos.taille + 0.703));
+ return 0.109*mos.bras + 0.093*mos.cuisse + 0.276*mos.avantBras + 0.078*mos.abdomen - 0.056*mos.taille + 0.703;
+ }
+
@Override
public void onTerminate() {
super.onTerminate();
@@ -145,6 +156,113 @@ public class EMorphApplication extends Application {
return new MeasureOnSubject(newId, subjectId, abdomen, bras, epaules, taille, cuisse, cheville, avantBras);
}
+ public Long getLastMeasureID(long groupID) {
+ Cursor dbResult = db.query("measures",new String[]{"ID"},
+ "groupID=?",new String[]{Long.toString(groupID)}, null, null, "time DESC");
+ dbResult.moveToFirst();
+ Long out;
+ if(dbResult.isAfterLast())
+ out = null;
+ else
+ out = dbResult.getLong(0);
+ dbResult.close();
+ return out;
+ }
+
+ public Set getXLastMeasures(long groupID, int x){
+ Cursor dbResult = db.query("measures",new String[]{"ID"},
+ "groupID=?",new String[]{Long.toString(groupID)}, null, null, "time DESC");
+ dbResult.moveToFirst();
+ Set out = new HashSet<>();
+ for(int i=0;i getMeasuresIDs(long groupID){
+ Cursor dbResult = db.query("measures",new String[]{"ID"},
+ "groupID=?",new String[]{Long.toString(groupID)}, null, null, null);
+ dbResult.moveToFirst();
+ Set out = new HashSet<>();
+ while(!dbResult.isAfterLast()) {
+ out.add(dbResult.getLong(0));
+ dbResult.moveToNext();
+ }
+ dbResult.close();
+ return out;
+ }
+
+ public Set getMeasuresSince(long groupID, long oldDate) {
+ Cursor dbResult = db.query("measures",new String[]{"ID"},
+ "groupID=? AND time>?",new String[]{Long.toString(groupID),Long.toString(oldDate)},
+ null, null, null);
+ dbResult.moveToFirst();
+ Set out = new HashSet<>();
+ while(!dbResult.isAfterLast()) {
+ out.add(dbResult.getLong(0));
+ dbResult.moveToNext();
+ }
+ dbResult.close();
+ return out;
+ }
+ public MeasureOnSubject getMos(long subjectID, long measureID){
+ Cursor dbResult = db.query("measuresOnSubjects",new String[]{"ID","subjectID","circAbdomen","circBras","circEpaules","circTaille","circCuisse","circCheville","circAvantBras"},
+ "subjectID = ?",new String[]{Long.toString(subjectID)/*,Long.toString(measureID)*/},
+ null, null, null);
+ dbResult.moveToFirst();
+ MeasureOnSubject out;
+ if(dbResult.isAfterLast())
+ out = null;
+ else
+ out = new MeasureOnSubject(
+ dbResult.getLong(0),
+ dbResult.getLong(1),
+ dbResult.getFloat(2),
+ dbResult.getFloat(3),
+ dbResult.getFloat(4),
+ dbResult.getFloat(5),
+ dbResult.getFloat(6),
+ dbResult.getFloat(7),
+ dbResult.getFloat(8)
+ );
+ dbResult.close();
+ return out;
+ }
+
+ public long dateNaissance(long subjectID){
+ Cursor result = db.query("subjects",new String[]{"dateNaissance"},"ID=?", new String[]{Long.toString(subjectID)},null,null,null);
+ if(result.getCount()==0)return -1;
+ result.moveToFirst();
+ long out = result.getLong(0);
+ result.close();
+ return out;
+ }
+
+ public void dumpTable(String tableName){
+ Cursor c = db.rawQuery("SELECT * FROM "+tableName,new String[0]);
+ c.moveToFirst();
+ StringBuilder sb = new StringBuilder("Dumping table "+tableName+" :\n");
+ while(!c.isAfterLast()){
+ for(int i=0;i {
+
+ /**
+ * paint to do drawing on canvas
+ */
+ private final Paint mPaint;
+
+ /**
+ * stores the coordinates of the bars to
+ * trigger tap on series events.
+ */
+ private final Map mDataPoints = new HashMap<>();
+
+ /**
+ * creates bar series with data
+ *
+ * @param data data points
+ * important: array has to be sorted from lowest x-value to the highest
+ */
+ public SquaringGraphSeries(SquaringGraphSeries.DirectionalRectanglePoint[] data) {
+ super(data);
+ mPaint = new Paint();
+ }
+
+ /**
+ * draws the bars on the canvas
+ *
+ * @param graphView corresponding graphview
+ * @param canvas canvas
+ * @param isSecondScale whether we are plotting the second scale or not
+ */
+ @Override
+ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) {
+
+ resetDataPoints();
+
+ // get data
+ double maxX = graphView.getViewport().getMaxX(false);
+ double minX = graphView.getViewport().getMinX(false);
+
+ double maxY;
+ double minY;
+ if (isSecondScale) {
+ maxY = graphView.getSecondScale().getMaxY(false);
+ minY = graphView.getSecondScale().getMinY(false);
+ } else {
+ maxY = graphView.getViewport().getMaxY(false);
+ minY = graphView.getViewport().getMinY(false);
+ }
+
+ /*
+ // Iterate through all bar graph series
+ // so we know how wide to make our bar,
+ // and in what position to put it in
+ int numBarSeries = 0;
+ int currentSeriesOrder = 0;
+ int numValues = 0;
+ boolean isCurrentSeries;
+ SortedSet xVals = new TreeSet();
+ for(Series> inspectedSeries: graphView.getSeries()) {
+ if(inspectedSeries instanceof SquaringGraphSeries) {
+ isCurrentSeries = (inspectedSeries == this);
+ if(isCurrentSeries) {
+ currentSeriesOrder = numBarSeries;
+ }
+ numBarSeries++;
+
+ // calculate the number of slots for bars based on the minimum distance between
+ // x coordinates in the series. This is divided into the range to find
+ // the placement and width of bar slots
+ // (sections of the x axis for each bar or set of bars)
+ // TODO: Move this somewhere more general and cache it, so we don't recalculate it for each series
+ Iterator> curValues = inspectedSeries.getValues(minX, maxX);
+ if (curValues.hasNext()) {
+ xVals.add(((DirectionalRectanglePoint)curValues.next()).getX());
+ if(isCurrentSeries) { numValues++; }
+ while (curValues.hasNext()) {
+ xVals.add(((DirectionalRectanglePoint)curValues.next()).getX());
+ if(isCurrentSeries) { numValues++; }
+ }
+ }
+ }
+ }
+ if (numValues == 0) {
+ return;
+ }
+
+ double minGap = 0;
+
+ if(mDataWidth > 0.0) {
+ minGap = mDataWidth;
+ } else {
+ Double lastVal = null;
+
+ for(Double curVal: xVals) {
+ if(lastVal != null) {
+ double curGap = Math.abs(curVal - lastVal);
+ if (minGap == 0 || (curGap > 0 && curGap < minGap)) {
+ minGap = curGap;
+ }
+ }
+ lastVal = curVal;
+ }
+ }
+
+ int numBarSlots = (minGap == 0) ? 1 : (int)Math.round((maxX - minX)/minGap) + 1;
+ */
+
+ Iterator values = getValues(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+
+ // Calculate the overall bar slot width - this includes all bars across
+ // all series, and any spacing between sets of bars
+
+ double diffY = maxY - minY;
+ double diffX = maxX - minX;
+ double contentHeight = graphView.getGraphContentHeight();
+ double contentWidth = graphView.getGraphContentWidth();
+ double contentLeft = graphView.getGraphContentLeft();
+ double contentTop = graphView.getGraphContentTop();
+
+ // draw data
+ while (values.hasNext()) {
+ SquaringGraphSeries.DirectionalRectanglePoint value = values.next();
+
+ double top = contentTop + (maxY-value.top)*contentHeight/diffY;
+
+ double bottom = contentTop + (maxY-value.bottom)*contentHeight/diffY;
+
+ double left = contentLeft + contentWidth*(value.left-minX)/diffX;
+
+ double right = contentLeft + contentWidth*(value.right-minX)/diffX;
+
+
+ // hook for value dependent color
+ if (value.color != -1) {
+ int ncol = value.color&0xFFFFFF, nalp = value.color>>24;
+ mPaint.setColor(ncol);
+ mPaint.setAlpha(nalp);
+ } else {
+ mPaint.setColor(getColor());
+ }
+
+
+ // overdraw
+ top = forceBetween(top, contentTop, contentTop+contentHeight);
+ right = forceBetween(right, contentLeft,contentLeft+contentWidth);
+ bottom = forceBetween(bottom, contentTop, contentTop+contentHeight);
+ left = forceBetween(left, contentLeft,contentLeft+contentWidth);
+ Log.d("SquaringGraphDrawer","Drawing rectangle "+top+";"+left+";"+bottom+";"+right);
+
+ mDataPoints.put(new RectD(left, top, right, bottom), value);
+
+ canvas.drawRect((float)left, (float)top, (float)right, (float)bottom, mPaint);
+
+ /*
+ // set values on top of graph
+ if (mDrawValuesOnTop) {
+ if (reverse) {
+ top = bottom + mValuesOnTopSize + 4;
+ if (top > contentTop+contentHeight) top = contentTop + contentHeight;
+ } else {
+ top -= 4;
+ if (top<=contentTop) top+=contentTop+4;
+ }
+
+ mPaint.setColor(mValuesOnTopColor);
+ canvas.drawText(
+ graphView.getGridLabelRenderer().getLabelFormatter().formatLabel(value.getY(), false)
+ , (float) (left+right)/2, (float) top, mPaint);
+ }
+ */
+ }
+ }
+
+ public static double forceBetween(double value, double min, double max){
+ return Math.max(Math.min(value,max),min);
+ }
+
+ /**
+ * resets the cached coordinates of the bars
+ */
+ @Override
+ protected void resetDataPoints() {
+ mDataPoints.clear();
+ }
+
+ /**
+ * find the corresponding data point by
+ * coordinates.
+ *
+ * @param x pixels
+ * @param y pixels
+ * @return datapoint or null
+ */
+ @Override
+ protected SquaringGraphSeries.DirectionalRectanglePoint findDataPoint(float x, float y) {
+ for (Map.Entry entry : mDataPoints.entrySet()) {
+ if (x >= entry.getKey().left && x <= entry.getKey().right
+ && y >= entry.getKey().top && y <= entry.getKey().bottom) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void drawSelection(GraphView mGraphView, Canvas canvas, boolean b, DataPointInterface value) {
+ // We do nothing more
+ }
+
+ public static class DirectionalRectanglePoint implements DataPointInterface {
+
+ double top,left,bottom,right;
+ int color;
+
+ public DirectionalRectanglePoint(double top, double left, double bottom, double right, int color) {
+ this.top = top;
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ this.color = color;
+ }
+
+ @Override
+ public double getX() {
+ return left;
+ }
+
+ @Override
+ public double getY() {
+ return top;
+ }
+ }
+}
diff --git a/app/src/main/java/com/bernard/emorph/activities/GraphActivity.java b/app/src/main/java/com/bernard/emorph/activities/GraphActivity.java
index a536bd7..30210e6 100644
--- a/app/src/main/java/com/bernard/emorph/activities/GraphActivity.java
+++ b/app/src/main/java/com/bernard/emorph/activities/GraphActivity.java
@@ -1,14 +1,167 @@
package com.bernard.emorph.activities;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+
import androidx.appcompat.app.AppCompatActivity;
-import android.os.Bundle;
+import com.bernard.emorph.EMorphApplication;
+import com.bernard.emorph.R;
+import com.bernard.emorph.SquaringGraphSeries;
+import com.bernard.emorph.model.ToGraph;
+import com.jjoe64.graphview.GraphView;
+import com.jjoe64.graphview.Viewport;
+import com.jjoe64.graphview.series.DataPoint;
+import com.jjoe64.graphview.series.PointsGraphSeries;
+import com.jjoe64.graphview.series.Series;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Random;
public class GraphActivity extends AppCompatActivity {
+ public static final String TOGRAPH_TO_GRAPH_EXTRA = "com.bernard.emorph.activities.GraphActivity.toGraph";
+
+ ToGraph toGraph;
+ GraphView gv;
+ EMorphApplication theApp;
+ int[] colors;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_graph);
+
+ Intent theIntent = getIntent();
+ toGraph = theIntent.getParcelableExtra(TOGRAPH_TO_GRAPH_EXTRA);
+
+ theApp = (EMorphApplication) getApplication();
+
+ gv = findViewById(R.id.theGraphView);
+
+ String[] cs = getResources().getStringArray(R.array.distinctGraphColors);
+ colors = new int[cs.length];
+ for (int i = 0; i < colors.length; i++)
+ colors[i] = Integer.parseInt(cs[i].substring(1),16);
+
+
+ initGraph();
+
+ }
+
+ public static final double MEGA_MAX_IMG = 50;
+ public static final double MEGA_MIN_IMG = -50;
+ public static final double MEGA_MAX_IMM = 100;
+ public static final double MEGA_MIN_IMM = 0;
+
+
+ public void initGraph(){
+
+ int subjectCount = toGraph.getSubjectsID().length;
+ DataPoint[] points0 = new DataPoint[subjectCount];
+ double minx=1e10f,maxx=0f,miny=1e10f,maxy=0f;
+ PointsGraphSeries[] pgs = new PointsGraphSeries[toGraph.getMeasuresID().length];
+ for(int j=0; jpoints0[i].getX())minx = points0[i].getX();
+ if(maxxpoints0[i].getY())miny = points0[i].getY();
+ if(maxy(d1==null)?((d2==null)?0:-1):((d2==null)?1:Double.compare(d1.getX(),d2.getX())));
+ DataPoint[] points = new DataPoint[realSize];
+ System.arraycopy(points0,0,points,0,realSize);
+ PointsGraphSeries series = new PointsGraphSeries<>(points);
+ series.setShape(PointsGraphSeries.Shape.POINT);
+ series.setColor(colors[j]|0xFF000000);
+ series.setSize(10);
+ pgs[j] = series;
+ Log.d("NewSeries","Nouvelle serie de "+realSize+" points: couleur #"+Integer.toHexString(colors[j]));
+ }
+
+
+ // Calcul des valeurs limites
+ double moyIMM, sdIMM, moyIMG, sdIMG;
+ switch(toGraph.getBase()){
+ case LABO_U11:
+ moyIMM=14.9;
+ sdIMM=1.3;
+ moyIMG=4.4;
+ sdIMG=2.5;
+ break;
+ case LABO_U13:
+ moyIMM=15.6;
+ sdIMM=1.8;
+ moyIMG=4.7;
+ sdIMG=1.9;
+ break;
+ case LABO_U15:
+ moyIMM=18.5;
+ sdIMM=2.0;
+ moyIMG=6.7;
+ sdIMG=2.4;
+ break;
+ default:
+ // Là on s'amuse
+ // On prend la moyenne et l'ecart type d'absolument toutes les valeurs.
+ moyIMM = sdIMM = moyIMG = sdIMG = 0;
+ int c = 0;
+ for(PointsGraphSeries> s : pgs){
+ Iterator> it = s.getValues(s.getLowestValueX(),s.getHighestValueX());
+ while(it.hasNext()){
+ DataPoint dp = (DataPoint) it.next(); // Ne devrait pas poser de problème.
+ moyIMM += dp.getX();
+ sdIMM += dp.getX()*dp.getX();
+ moyIMG += dp.getY();
+ sdIMG += dp.getY()*dp.getY();
+ c++;
+ }
+ }
+ moyIMM /= c;
+ moyIMG /= c;
+ sdIMM = Math.sqrt((sdIMM/c)-moyIMM*moyIMM);
+ sdIMG = Math.sqrt((sdIMG/c)-moyIMG*moyIMG); // Je crois que les formules sont bonnes.
+ }
+
+ Viewport theVP = gv.getViewport();
+ theVP.setXAxisBoundsManual(true);
+ theVP.setMinX(Math.min(minx,moyIMM-sdIMM)-.4);
+ theVP.setMaxX(Math.max(maxx,moyIMM+sdIMM)+.4);
+ theVP.setYAxisBoundsManual(true);
+ theVP.setMinY(Math.min(miny,moyIMG-sdIMG)-.4);
+ theVP.setMaxY(Math.max(maxy,moyIMG+sdIMG)+.4);
+
+ int interColor = 0x53FFFF00;
+ int extremeColor = 0x53FF0000;
+
+ SquaringGraphSeries sgs = new SquaringGraphSeries(new SquaringGraphSeries.DirectionalRectanglePoint[]{
+ new SquaringGraphSeries.DirectionalRectanglePoint(MEGA_MAX_IMG ,MEGA_MIN_IMM ,moyIMG+sdIMG,moyIMM-sdIMM,extremeColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(moyIMG-sdIMG,MEGA_MIN_IMM ,MEGA_MIN_IMG,moyIMM-sdIMM,extremeColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(moyIMG+sdIMG,MEGA_MIN_IMM ,moyIMG-sdIMG,moyIMM-sdIMM,interColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(MEGA_MAX_IMG ,moyIMM-sdIMM,moyIMG+sdIMG,moyIMM+sdIMM,interColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(moyIMG-sdIMG,moyIMM-sdIMM,MEGA_MIN_IMG,moyIMM+sdIMM, interColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(MEGA_MAX_IMG ,moyIMM+sdIMM,moyIMG+sdIMG,MEGA_MAX_IMM,extremeColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(moyIMG-sdIMG,moyIMM+sdIMM,MEGA_MIN_IMG,MEGA_MAX_IMM,extremeColor),
+ new SquaringGraphSeries.DirectionalRectanglePoint(moyIMG+sdIMG,moyIMM+sdIMM,moyIMG-sdIMG,MEGA_MAX_IMM,interColor)
+ });
+
+ gv.addSeries(sgs);
+
+ for (PointsGraphSeries> pg : pgs) gv.addSeries(pg);
+
+ }
+
+ public final int randCol(){
+ Random r = new Random();
+ return Color.HSVToColor(255, new float[]{r.nextFloat()*360,1.0f,1.0f});
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/bernard/emorph/activities/GroupListActivity.java b/app/src/main/java/com/bernard/emorph/activities/GroupListActivity.java
index 58709b2..aef2486 100644
--- a/app/src/main/java/com/bernard/emorph/activities/GroupListActivity.java
+++ b/app/src/main/java/com/bernard/emorph/activities/GroupListActivity.java
@@ -49,6 +49,11 @@ public class GroupListActivity extends AppCompatActivity {
}
+ public void startGraphGroup(Group g){
+ Intent theIntent = new Intent(this, PrepareGraphActivity.class);
+ theIntent.putExtra(PrepareGraphActivity.GROUPID_TO_GRAPH_EXTRA, g.id);
+ startActivity(theIntent);
+ }
public void startModifyGroup(Group g){
Intent theIntent = new Intent(this, EditSubjectListActivity.class);
theIntent.putExtra(EditSubjectListActivity.GROUPID_EXTRA, g.id);
@@ -81,6 +86,9 @@ public class GroupListActivity extends AppCompatActivity {
this.newDataButton = buttonsLayout.findViewById(R.id.new_data_button);
this.modifyGroupButton = buttonsLayout.findViewById(R.id.modify_group_button);
+ this.dataViewButton.setOnClickListener((e)->{
+ if(selectedIndex!=groups.size())startGraphGroup(groups.get(selectedIndex));
+ });
this.modifyGroupButton.setOnClickListener((e)->{
if(selectedIndex==groups.size())
startNewGroup();
diff --git a/app/src/main/java/com/bernard/emorph/activities/NewMeasureActivity.java b/app/src/main/java/com/bernard/emorph/activities/NewMeasureActivity.java
index 920aa17..77e49b0 100644
--- a/app/src/main/java/com/bernard/emorph/activities/NewMeasureActivity.java
+++ b/app/src/main/java/com/bernard/emorph/activities/NewMeasureActivity.java
@@ -109,6 +109,8 @@ public class NewMeasureActivity extends AppCompatActivity {
.show();
return;
}
+
+ finish();
}
class SubjectListAdapter extends RecyclerView.Adapter {
diff --git a/app/src/main/java/com/bernard/emorph/activities/PrepareGraphActivity.java b/app/src/main/java/com/bernard/emorph/activities/PrepareGraphActivity.java
new file mode 100644
index 0000000..4fb78f2
--- /dev/null
+++ b/app/src/main/java/com/bernard/emorph/activities/PrepareGraphActivity.java
@@ -0,0 +1,252 @@
+package com.bernard.emorph.activities;
+
+import android.app.DatePickerDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.NumberPicker;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bernard.emorph.EMorphApplication;
+import com.bernard.emorph.R;
+import com.bernard.emorph.model.Subject;
+import com.bernard.emorph.model.ToGraph;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class PrepareGraphActivity extends AppCompatActivity {
+
+ public static final String GROUPID_TO_GRAPH_EXTRA = "com.bernard.emorph.activities.PrepareGraphActivity.GroupIDToGraph";
+
+ long groupID;
+
+ Spinner measuresSelectorSpinner;
+ Set selectedMeasuresIDs;
+
+ CheckBox everySubjectCheckbox;
+ List subjects;
+ Set selectedSubjects;
+ RecyclerView rv;
+
+ Spinner basisSelectorSpinner;
+
+ Button okButton;
+
+ EMorphApplication theApp;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_prepare_graph);
+
+ Intent theIntent = getIntent();
+ groupID = theIntent.getLongExtra(GROUPID_TO_GRAPH_EXTRA,-1L);
+
+ theApp = (EMorphApplication) getApplication();
+
+ measuresSelectorSpinner = findViewById(R.id.measureSelector);
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
+ R.array.measureSelectorsTypes, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ measuresSelectorSpinner.setAdapter(adapter);
+
+ everySubjectCheckbox = findViewById(R.id.everySubjectCheckbox);
+
+ rv = findViewById(R.id.subjectsList);
+ SubjectListAdapter sla = new SubjectListAdapter();
+ rv.setAdapter(sla);
+ rv.setLayoutManager(new LinearLayoutManager(this));
+
+ basisSelectorSpinner = findViewById(R.id.basisSelector);
+ ArrayAdapter adapter2 = ArrayAdapter.createFromResource(this,
+ R.array.basisTypes, android.R.layout.simple_spinner_item);
+ adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ basisSelectorSpinner.setAdapter(adapter2);
+
+ okButton = findViewById(R.id.okButton);
+
+
+ selectedMeasuresIDs = Collections.singleton(theApp.getLastMeasureID(groupID));
+ measuresSelectorSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+
+ switch(i){
+ case 0: // Dernière
+ selectedMeasuresIDs = Collections.singleton(theApp.getLastMeasureID(groupID));
+ return;
+ case 1: // 5 dernières
+ selectedMeasuresIDs = theApp.getXLastMeasures(groupID, 5);
+ return;
+ case 2: // x dernières
+
+ final AlertDialog.Builder d = new AlertDialog.Builder(PrepareGraphActivity.this);
+ LayoutInflater inflater = PrepareGraphActivity.this.getLayoutInflater();
+ View dialogView = inflater.inflate(R.layout.number_picker_dialog, null);
+ d.setTitle(R.string.measureCountDialogTitle);
+ d.setMessage(R.string.measureCountDialogMessage);
+ d.setView(dialogView);
+ final NumberPicker numberPicker = (NumberPicker) dialogView.findViewById(R.id.dialog_number_picker);
+ numberPicker.setMaxValue(100);
+ numberPicker.setMinValue(1);
+ numberPicker.setWrapSelectorWheel(false);
+ d.setPositiveButton(android.R.string.ok, (di,j)->selectedMeasuresIDs = theApp.getXLastMeasures(groupID, numberPicker.getValue()));
+ d.setNegativeButton(android.R.string.cancel, (di,j)->selectedMeasuresIDs = Collections.singleton(theApp.getLastMeasureID(groupID)));
+ AlertDialog alertDialog = d.create();
+ alertDialog.show();
+ return;
+ case 3: // à partir du
+ Calendar mcurrentDate=Calendar.getInstance();
+ int year = mcurrentDate.get(Calendar.YEAR);
+ int month = mcurrentDate.get(Calendar.MONTH);
+ int day = mcurrentDate.get(Calendar.DAY_OF_MONTH);
+ DatePickerDialog mDatePicker=new DatePickerDialog(PrepareGraphActivity.this,
+ (datepicker, selectedYear, selectedMonth, selectedDay) -> {
+ Log.d("Date Selected", "Month: " + selectedMonth + " Day: " + selectedDay + " Year: " + selectedYear);
+ Calendar selected = Calendar.getInstance();
+ selected.set(selectedYear, selectedMonth, selectedDay);
+
+ selectedMeasuresIDs = theApp.getMeasuresSince(groupID, selected.getTimeInMillis()/1000);
+ },year, month, day);
+ mDatePicker.setOnDismissListener((e) -> measuresSelectorSpinner.setSelection(0));
+ mDatePicker.setOnCancelListener((e) -> measuresSelectorSpinner.setSelection(0));
+ mDatePicker.setTitle(R.string.sinceWhenDialog);
+ mDatePicker.show();
+ return;
+ case 4: // Toutes
+ selectedMeasuresIDs = theApp.getMeasuresIDs(groupID);
+ return;
+ default: // Spécifique
+ //TODO: Faire un dialog permetant de sélectionner les mesures
+ selectedMeasuresIDs = Collections.singleton(theApp.getLastMeasureID(groupID));
+ measuresSelectorSpinner.setSelection(0);
+ Toast.makeText(PrepareGraphActivity.this, R.string.notImplementedYet, Toast.LENGTH_SHORT).show();
+ }
+
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+ selectedMeasuresIDs = Collections.emptySet();
+ }
+ });
+
+ everySubjectCheckbox.setSelected(true);
+ rv.setEnabled(false);
+ everySubjectCheckbox.setOnCheckedChangeListener((e,b)-> {rv.setEnabled(!b);Log.d("Résultat","Check: "+b+"; Enablé: "+rv.isEnabled());});
+
+ subjects = theApp.getSubjects(groupID);
+ selectedSubjects = new HashSet<>();
+ for(Subject s : subjects)
+ selectedSubjects.add(s.id);
+
+
+ okButton.setOnClickListener((e)->drawGraph());
+
+ }
+
+ public ToGraph.Base selectedBasis(){
+ //TODO Rework this
+ switch(basisSelectorSpinner.getSelectedItemPosition()) {
+ case 0:
+ return ToGraph.Base.LABO_U11;
+ case 1:
+ return ToGraph.Base.LABO_U13;
+ case 2:
+ return ToGraph.Base.LABO_U15;
+ default:
+ return ToGraph.Base.GROUPE;
+ }
+ }
+
+ public void drawGraph(){
+ ToGraph tg;
+ if(everySubjectCheckbox.isChecked())
+ tg = ToGraph.getS(selectedMeasuresIDs, subjects, selectedBasis());
+ else
+ tg = ToGraph.get(selectedMeasuresIDs, selectedSubjects, selectedBasis());
+
+ if(tg.getMeasuresID().length==0 || tg.getSubjectsID().length==0){
+ Toast.makeText(this, R.string.cantGraphNoInput, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Intent drawGraphIntent = new Intent(this, GraphActivity.class);
+ drawGraphIntent.putExtra(GraphActivity.TOGRAPH_TO_GRAPH_EXTRA, tg);
+ startActivity(drawGraphIntent);
+
+ }
+
+
+
+
+
+
+
+
+ class SubjectListAdapter extends RecyclerView.Adapter {
+
+ public SubjectListAdapter(){}
+
+ @NonNull
+ @Override
+ public PrepareGraphActivity.SubjectListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View theView = LayoutInflater.from(parent.getContext()).inflate(R.layout.preparegraph_subject_list_item, parent, false);
+
+ return new PrepareGraphActivity.SubjectListAdapter.ViewHolder(theView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull PrepareGraphActivity.SubjectListAdapter.ViewHolder holder, int position) {
+ holder.titleText.setText(subjects.get(position).name);
+
+ holder.subjectBox.setOnCheckedChangeListener((e,b) -> checkSubject(subjects.get(position),b));
+ }
+
+ public void checkSubject(Subject s, boolean isChecked){
+ if(isChecked)
+ selectedSubjects.add(s.id);
+ else
+ selectedSubjects.remove(s.id);
+ }
+
+ @Override
+ public int getItemCount() {
+ return subjects.size();
+ }
+
+
+ class ViewHolder extends RecyclerView.ViewHolder{
+
+ TextView titleText;
+ CheckBox subjectBox;
+ View theView;
+
+ public ViewHolder(View theView) {
+ super(theView);
+ this.theView = theView;
+ this.titleText = theView.findViewById(R.id.subjectNameText);
+ this.subjectBox = theView.findViewById(R.id.subjectCheckbox);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/bernard/emorph/model/MeasureOnSubject.java b/app/src/main/java/com/bernard/emorph/model/MeasureOnSubject.java
index 2154844..9454d6d 100644
--- a/app/src/main/java/com/bernard/emorph/model/MeasureOnSubject.java
+++ b/app/src/main/java/com/bernard/emorph/model/MeasureOnSubject.java
@@ -64,4 +64,19 @@ public class MeasureOnSubject implements Parcelable {
p.writeFloat(cheville);
p.writeFloat(avantBras);
}
+
+ @Override
+ public String toString() {
+ return "MeasureOnSubject{" +
+ "mosId=" + mosId +
+ ", subjectID=" + subjectID +
+ ", abdomen=" + abdomen +
+ ", bras=" + bras +
+ ", epaules=" + epaules +
+ ", taille=" + taille +
+ ", cuisse=" + cuisse +
+ ", cheville=" + cheville +
+ ", avantBras=" + avantBras +
+ '}';
+ }
}
diff --git a/app/src/main/java/com/bernard/emorph/model/ToGraph.java b/app/src/main/java/com/bernard/emorph/model/ToGraph.java
index bf7e1e8..e49bb6e 100644
--- a/app/src/main/java/com/bernard/emorph/model/ToGraph.java
+++ b/app/src/main/java/com/bernard/emorph/model/ToGraph.java
@@ -1,6 +1,11 @@
package com.bernard.emorph.model;
-public class ToGraph {
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collection;
+
+public class ToGraph implements Parcelable {
long[] measuresID;
@@ -8,8 +13,86 @@ public class ToGraph {
Base base;
- enum Base {
- LABO, GROUPE;
+ public enum Base {
+ LABO_U11, LABO_U13, LABO_U15, GROUPE
+ }
+ public ToGraph(long[] measuresID, long[] subjectsID, Base base) {
+ this.measuresID = measuresID;
+ this.subjectsID = subjectsID;
+ this.base = base;
+ }
+
+ public static ToGraph get(Collection measuresID, Collection subjectsID, Base base) {
+ return new ToGraph(longCollectionToLongArray(measuresID),longCollectionToLongArray(subjectsID),base);
+ }
+
+ public static ToGraph getS(Collection measuresID, Collection subjects, Base base) {
+ return new ToGraph(longCollectionToLongArray(measuresID),subjectsCollectionToLongArray(subjects),base);
+ }
+
+ private ToGraph(Parcel p){
+ this.measuresID = new long[p.readInt()];
+ p.readLongArray(this.measuresID);
+ this.subjectsID = new long[p.readInt()];
+ p.readLongArray(this.subjectsID);
+ base = Base.values()[p.readInt()];
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ToGraph createFromParcel(Parcel parcel) {
+ return new ToGraph(parcel);
+ }
+
+ @Override
+ public ToGraph[] newArray(int i) {
+ return new ToGraph[i];
+ }
+ };
+
+ public long[] getMeasuresID() {
+ return measuresID;
+ }
+
+ public long[] getSubjectsID() {
+ return subjectsID;
+ }
+
+ public Base getBase() {
+ return base;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeInt(measuresID.length);
+ parcel.writeLongArray(this.measuresID);
+ parcel.writeInt(subjectsID.length);
+ parcel.writeLongArray(this.subjectsID);
+ parcel.writeInt(base.ordinal());
+ }
+
+ public static long[] longCollectionToLongArray(Collection c){
+ long[] mi = new long[c.size()];
+ int i=0;
+ for(Long m : c){
+ mi[i] = m;
+ i++;
+ }
+ return mi;
+ }
+ public static long[] subjectsCollectionToLongArray(Collection c){
+ long[] mi = new long[c.size()];
+ int i=0;
+ for(Subject s : c){
+ mi[i] = s.id;
+ i++;
+ }
+ return mi;
}
}
diff --git a/app/src/main/res/layout/activity_graph.xml b/app/src/main/res/layout/activity_graph.xml
index 86102ac..acad465 100644
--- a/app/src/main/res/layout/activity_graph.xml
+++ b/app/src/main/res/layout/activity_graph.xml
@@ -1,9 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_prepare_graph.xml b/app/src/main/res/layout/activity_prepare_graph.xml
new file mode 100644
index 0000000..86255ad
--- /dev/null
+++ b/app/src/main/res/layout/activity_prepare_graph.xml
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/number_picker_dialog.xml b/app/src/main/res/layout/number_picker_dialog.xml
new file mode 100644
index 0000000..aca4ab2
--- /dev/null
+++ b/app/src/main/res/layout/number_picker_dialog.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/preparegraph_subject_list_item.xml b/app/src/main/res/layout/preparegraph_subject_list_item.xml
new file mode 100644
index 0000000..e839a7b
--- /dev/null
+++ b/app/src/main/res/layout/preparegraph_subject_list_item.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..e1d87cf
--- /dev/null
+++ b/app/src/main/res/values/arrays.xml
@@ -0,0 +1,21 @@
+
+
+
+ - @string/lab11Basis
+ - @string/lab13Basis
+ - @string/lab15Basis
+ - @string/localBasis
+
+
+
+ - @string/lastMeasure
+ - @string/last5Measures
+ - @string/xlastMeasures
+ - @string/sinceMeasures
+ - @string/everyMeasure
+ - @string/customMeasures
+
+ Données U11
+ Données U13
+ Données U15
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f8c6127..11d020e 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,136 @@
#FF018786
#FF000000
#FFFFFFFF
+
+
+
+ - #000000
+ - #FFFF00
+ - #1CE6FF
+ - #FF34FF
+ - #FF4A46
+ - #008941
+ - #006FA6
+ - #A30059
+ - #FFDBE5
+ - #7A4900
+ - #0000A6
+ - #63FFAC
+ - #B79762
+ - #004D43
+ - #8FB0FF
+ - #997D87
+ - #5A0007
+ - #809693
+ - #FEFFE6
+ - #1B4400
+ - #4FC601
+ - #3B5DFF
+ - #4A3B53
+ - #FF2F80
+ - #61615A
+ - #BA0900
+ - #6B7900
+ - #00C2A0
+ - #FFAA92
+ - #FF90C9
+ - #B903AA
+ - #D16100
+ - #DDEFFF
+ - #000035
+ - #7B4F4B
+ - #A1C299
+ - #300018
+ - #0AA6D8
+ - #013349
+ - #00846F
+ - #372101
+ - #FFB500
+ - #C2FFED
+ - #A079BF
+ - #CC0744
+ - #C0B9B2
+ - #C2FF99
+ - #001E09
+ - #00489C
+ - #6F0062
+ - #0CBD66
+ - #EEC3FF
+ - #456D75
+ - #B77B68
+ - #7A87A1
+ - #788D66
+ - #885578
+ - #FAD09F
+ - #FF8A9A
+ - #D157A0
+ - #BEC459
+ - #456648
+ - #0086ED
+ - #886F4C
+ - #34362D
+ - #B4A8BD
+ - #00A6AA
+ - #452C2C
+ - #636375
+ - #A3C8C9
+ - #FF913F
+ - #938A81
+ - #575329
+ - #00FECF
+ - #B05B6F
+ - #8CD0FF
+ - #3B9700
+ - #04F757
+ - #C8A1A1
+ - #1E6E00
+ - #7900D7
+ - #A77500
+ - #6367A9
+ - #A05837
+ - #6B002C
+ - #772600
+ - #D790FF
+ - #9B9700
+ - #549E79
+ - #FFF69F
+ - #201625
+ - #72418F
+ - #BC23FF
+ - #99ADC0
+ - #3A2465
+ - #922329
+ - #5B4534
+ - #FDE8DC
+ - #404E55
+ - #0089A3
+ - #CB7E98
+ - #A4E804
+ - #324E72
+ - #6A3A4C
+ - #83AB58
+ - #001C1E
+ - #D1F7CE
+ - #004B28
+ - #C8D0F6
+ - #A3A489
+ - #806C66
+ - #222800
+ - #BF5650
+ - #E83000
+ - #66796D
+ - #DA007C
+ - #FF1A59
+ - #8ADBB4
+ - #1E0200
+ - #5B4E51
+ - #C895C5
+ - #320033
+ - #FF6832
+ - #66E1D3
+ - #CFCDAC
+ - #D0AC94
+ - #7ED379
+ - #012C58
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a4387f6..79347dd 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,5 +48,24 @@
Terminer la mesure
Terminer la mesure ?
Voulez-vous vraiment terminer la mesure, bien que %s n\'ai pas de nouvelle entrée ?
-
+ "Mesure : "
+ Tous
+ "Base : "
+ Dessiner !
+ Échantillon du labo
+ Échantillon local
+ Dernière
+ 5 dernières
+ x dernières
+ depuis le
+ Toutes
+ Défini
+ Aucune mesure ou aucun sujet sélectionné.
+ Nom du sujet
+ Depuis quelle date voulez vous voir les mesures ?
+ Selection des mesures
+ Combien de mesures en arrière faut-il observer ?
+ Fonctionnalitée pas encore implémentée.
+ Sélection des sujets
+ Préparation du graphique
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 3bb1708..a0b4f3c 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -11,6 +11,10 @@
+