From dbb108dd73aa6053901dbf4a3d0e0e64312a9700 Mon Sep 17 00:00:00 2001 From: Samy Avrillon Date: Fri, 10 Dec 2021 19:46:45 +0100 Subject: [PATCH] New version a bit more up to date. --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 5 +- .../com/bernard/emorph/EMorphApplication.java | 132 ++++++++- .../bernard/emorph/SquaringGraphSeries.java | 249 +++++++++++++++++ .../emorph/activities/GraphActivity.java | 155 ++++++++++- .../emorph/activities/GroupListActivity.java | 8 + .../emorph/activities/NewMeasureActivity.java | 2 + .../activities/PrepareGraphActivity.java | 252 ++++++++++++++++++ .../emorph/model/MeasureOnSubject.java | 15 ++ .../com/bernard/emorph/model/ToGraph.java | 89 ++++++- app/src/main/res/layout/activity_graph.xml | 7 +- .../res/layout/activity_prepare_graph.xml | 148 ++++++++++ .../main/res/layout/number_picker_dialog.xml | 13 + .../layout/preparegraph_subject_list_item.xml | 32 +++ app/src/main/res/values/arrays.xml | 21 ++ app/src/main/res/values/colors.xml | 132 +++++++++ app/src/main/res/values/strings.xml | 21 +- app/src/main/res/values/styles.xml | 4 + 18 files changed, 1271 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/bernard/emorph/SquaringGraphSeries.java create mode 100644 app/src/main/java/com/bernard/emorph/activities/PrepareGraphActivity.java create mode 100644 app/src/main/res/layout/activity_prepare_graph.xml create mode 100644 app/src/main/res/layout/number_picker_dialog.xml create mode 100644 app/src/main/res/layout/preparegraph_subject_list_item.xml create mode 100644 app/src/main/res/values/arrays.xml 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +