From b41ed2667c2fa818172c21720b0abc86c079396a Mon Sep 17 00:00:00 2001 From: Daniel Carta <79732052+immortaldan10@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:51:05 -0600 Subject: [PATCH] Testing 9/18 --- .../ridgescout/types/input/FieldType.java | 6 +- .../ridgescout/types/input/TallyType.java | 1 + .../ridgescout/types/input/ToggleType.java | 368 ++++++++++++++++++ .../ui/settings/FieldEditorHelper.java | 52 ++- 4 files changed, 423 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/ridgebotics/ridgescout/types/input/ToggleType.java diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/FieldType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/FieldType.java index 7c87116..9883d3e 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/FieldType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/FieldType.java @@ -24,6 +24,7 @@ public abstract class FieldType { public static final int numberType = 251; public static final int checkboxType = 250; public static final int fieldposType = 249; + public static final int toggleType = 248; public enum inputTypes { SLIDER, @@ -32,7 +33,8 @@ public abstract class FieldType { TALLY, NUMBER, CHECKBOX, - FIELDPOS + FIELDPOS, + TOGGLE; } public String UUID; public String name; @@ -89,8 +91,6 @@ public abstract class FieldType { public abstract void setViewValue(Object value); public abstract RawDataType getViewValue(); - - public abstract void add_individual_view(LinearLayout parent, RawDataType data); public abstract void add_compiled_view(LinearLayout parent, RawDataType[] data); public abstract void add_history_view(LinearLayout parent, RawDataType[] data); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/TallyType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/TallyType.java index c504e65..1b94e98 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/types/input/TallyType.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/TallyType.java @@ -65,6 +65,7 @@ public class TallyType extends FieldType { public TallyCounterView tally = null; + public View createView(Context context, Function onUpdate){ tally = new TallyCounterView(context); tally.setOnCountChangedListener(n -> onUpdate.apply(getViewValue())); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/types/input/ToggleType.java b/app/src/main/java/com/ridgebotics/ridgescout/types/input/ToggleType.java new file mode 100644 index 0000000..160827d --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/types/input/ToggleType.java @@ -0,0 +1,368 @@ +package com.ridgebotics.ridgescout.types.input; + +import static com.ridgebotics.ridgescout.utility.Colors.chart_background; +import static com.ridgebotics.ridgescout.utility.Colors.chart_text; +import static com.ridgebotics.ridgescout.utility.Colors.dropdown_value_text_1; +import static com.ridgebotics.ridgescout.utility.Colors.dropdown_value_text_2; +import static com.ridgebotics.ridgescout.utility.Colors.tally_data; + +import android.content.Context; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.components.Legend; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.data.LineDataSet; +import com.ridgebotics.ridgescout.types.data.IntType; +import com.ridgebotics.ridgescout.types.data.RawDataType; +import com.ridgebotics.ridgescout.ui.data.DataProcessing; +import com.ridgebotics.ridgescout.ui.views.CandlestickHeader; +import com.ridgebotics.ridgescout.ui.views.CandlestickView; +import com.ridgebotics.ridgescout.ui.views.TallyCounterView; +import com.ridgebotics.ridgescout.utility.BuiltByteParser; +import com.ridgebotics.ridgescout.utility.ByteBuilder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class ToggleType extends FieldType { + public int get_byte_id() {return toggleType;} + public inputTypes getInputType(){return inputTypes.TOGGLE;} + public RawDataType.valueTypes getValueType(){return RawDataType.valueTypes.NUM;} + public Object get_fallback_value(){return 0;} + public ToggleType(){} + public String get_type_name(){return "Toggle";} + public ToggleType(String UUID, String name, String description, int default_value){ + super(UUID, name, description); + this.default_value = default_value; + } + + + + + + public void encodeData(ByteBuilder bb) throws ByteBuilder.buildingException { + bb.addInt((int) default_value); + } + public void decodeData(ArrayList objects) { + default_value = objects.get(0).get(); + } + + + + + + public TallyCounterView tally = null; + + + public View createView(Context context, Function onUpdate){ + tally = new TallyCounterView(context); + tally.setOnCountChangedListener(n -> onUpdate.apply(getViewValue())); + + setViewValue(default_value); + + return tally; + + } + + public void setViewValue(Object value) { + if(tally == null) return; + if(IntType.isNull((int)value)){ + nullify(); + return; + } + + isBlank = false; + tally.setVisibility(View.VISIBLE); + tally.setValue((int) value); + } + public void nullify(){ + isBlank = true; + tally.setVisibility(View.GONE); + } + public RawDataType getViewValue(){ + if(tally == null) return null; + if(tally.getVisibility() == View.GONE) return IntType.newNull(name); + return new IntType(name, tally.getValue()); + } + + + + + + + public void add_individual_view(LinearLayout parent, RawDataType data){ + if(data.isNull()) return; + + TextView tv = new TextView(parent.getContext()); + tv.setLayoutParams(new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + tv.setGravity(Gravity.CENTER_HORIZONTAL); + tv.setText(String.valueOf((int) data.get())); + tv.setTextSize(24); + parent.addView(tv); + } + + + + + + + + + private static float calculateMean(int[] data) { + float sum = 0; + for (int value : data) { + sum += (float) value; + } + return sum / data.length; + } + + private static float calculateStandardDeviation(int[] data, float mean) { + float sum = 0; + for (int value : data) { + sum += (float) Math.pow((float) value - mean, 2); + } + return (float) Math.sqrt(sum / (data.length - 1)); + } + + private static List generateNormalDistribution(float mean, float stdDev, int count, int scale) { + List entries = new ArrayList<>(); + for (int i = 0; i < count; i++) { + float y = (float) ((1 / (stdDev * Math.sqrt(2 * Math.PI))) + * Math.exp(-0.5 * Math.pow(((float) i - mean) / stdDev, 2))); + entries.add(new Entry((float) i, y*scale)); // Scale y for visibility + } + return entries; + } + + private static int findMin(RawDataType[] data){ + int min = (int)data[0].get(); + for(int i = 1; i < data.length; i++) + if((int)data[i].get() < min) + min = (int)data[i].get(); + return min; + } + + private static int findMax(RawDataType[] data){ + int max = (int)data[0].get(); + for(int i = 1; i < data.length; i++) + if((int)data[i].get() > max) + max = (int)data[i].get(); + return max; + } + + public void add_compiled_view(LinearLayout parent, RawDataType[] data){ + LineChart chart = new LineChart(parent.getContext()); + FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + layout.height = 350; + chart.setLayoutParams(layout); + chart.setBackgroundColor(0xff252025); + + int min = findMin(data); + int max = findMax(data); + + int[] values = new int[max-min+1]; + + for (int i = 0; i < data.length; i++) + if(data[i] != null && data[i].isNull()) + values[(int) data[i].get()-min]++; + + + ArrayList mean_temp = new ArrayList<>(); + for (int i = 0; i < data.length; i++) + if((int)data[i].get() != 0) + mean_temp.add((int) data[i].get()); + + int[] mean_vals = mean_temp.stream().mapToInt(Integer::intValue).toArray(); + + List entries = new ArrayList<>(); + for (int i = 0; i < values.length; i++) + entries.add(new Entry(i, values[i])); + + + LineDataSet dataSet = new LineDataSet(entries, name); + dataSet.setColor(tally_data); + dataSet.setValueTextColor(dropdown_value_text_1); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + + + + // Calculate mean and standard deviation + float mean = calculateMean(mean_vals); + float stdDev = calculateStandardDeviation(mean_vals, mean); + + // Generate normal distribution curve + List normalDistEntries = generateNormalDistribution(mean-min, stdDev, max-min+1, (max-min)/data.length); + + + LineDataSet normalDistSet = new LineDataSet(normalDistEntries, "Normal Distribution"); + normalDistSet.setColor(dropdown_value_text_2); + normalDistSet.setDrawCircles(false); + normalDistSet.setDrawValues(false); + normalDistSet.setLineWidth(2f); + + LineData lineData = new LineData(dataSet, normalDistSet); + + chart.setData(lineData); + chart.invalidate(); + + chart.getDescription().setEnabled(false); + chart.setTouchEnabled(false); + chart.setDragEnabled(false); + chart.setScaleEnabled(false); + + dataSet.setValueTextColor(dropdown_value_text_2); + + chart.getXAxis().setTextColor(chart_text); + chart.getAxisLeft().setTextColor(chart_text); + chart.getAxisRight().setTextColor(chart_text); + + Legend legend = chart.getLegend(); + legend.setTextColor(chart_text); + + parent.addView(chart); + } + + + + + public void add_history_view(LinearLayout parent, RawDataType[] data){ + LineChart chart = new LineChart(parent.getContext()); + FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + layout.height = 350; + chart.setLayoutParams(layout); + chart.setBackgroundColor(chart_background); + + int min = findMin(data); + int max = findMax(data); + + List entries = new ArrayList<>(); + for (int i = 0; i < data.length; i++){ + if(data[i] == null) continue; + if(data[i].isNull()) continue; + + entries.add(new Entry(i, (float)(int) data[i].get())); + } + + + LineDataSet dataSet = new LineDataSet(entries, name); + dataSet.setColor(tally_data); + dataSet.setValueTextColor(dropdown_value_text_1); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + + LineData lineData = new LineData(dataSet); + + chart.setData(lineData); + chart.invalidate(); + + chart.getDescription().setEnabled(false); + chart.setTouchEnabled(false); + chart.setDragEnabled(false); + chart.setScaleEnabled(false); + + dataSet.setValueTextColor(dropdown_value_text_2); + + chart.getXAxis().setTextColor(chart_text); + chart.getAxisLeft().setTextColor(chart_text); + chart.getAxisRight().setTextColor(chart_text); + + Legend legend = chart.getLegend(); + legend.setTextColor(chart_text); + + + chart.getAxisLeft().setAxisMinimum(min); + chart.getAxisLeft().setAxisMaximum(max); + + chart.getAxisRight().setAxisMinimum(min); + chart.getAxisRight().setAxisMaximum(max); + + + parent.addView(chart); + } + + public void addDataToTable(TableLayout parent, Map> data){ + int[] tmp_abs_bounds = DataProcessing.getNumberBounds(data); + int absmin = tmp_abs_bounds[0]; + int absmax = tmp_abs_bounds[1]; + + //(int[]) teamData.get(i).get())[0]; +// AlertManager.alert("Results","Min: " + min + " Max: " + max); + + parent.removeAllViews(); + + List views = new ArrayList<>(); + + for(Integer teamNum : data.keySet()){ + CandlestickView candlestickView = new CandlestickView(parent.getContext()); + candlestickView.fromTeamData(data.get(teamNum), teamNum, absmin, absmax); + views.add(candlestickView); + } + + + TableRow row = new TableRow(parent.getContext()); + + // Make candlestick chart fill full width + parent.setColumnStretchable(1, true); + + // Fill in top left cell + row.addView(new View(parent.getContext())); + + CandlestickHeader header = new CandlestickHeader(parent.getContext()); + header.setScale(absmin, absmax); + row.addView(header); + + parent.addView(row); + +// parent.addView(new ); + + try { + Collections.sort(views, (a, b) -> (int) ((b.average - a.average) * 50.f)); + }catch (Exception e){} + + for(int i = 0; i < views.size(); i++){ + row = new TableRow(parent.getContext()); + CandlestickView view = views.get(i); + + TextView teamNum = new TextView(parent.getContext()); + TableRow.LayoutParams params = new TableRow.LayoutParams(); + params.gravity = Gravity.CENTER; + teamNum.setLayoutParams(params); + teamNum.setPadding(10,10,10,10); + teamNum.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6); + teamNum.setText(String.valueOf(view.teamNum)); + + + row.addView(teamNum); + row.addView(view); + + parent.addView(row); + } + } + + public String toString(RawDataType data){ + return String.valueOf((int) data.get()); + } +} + diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/FieldEditorHelper.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/FieldEditorHelper.java index c04da59..49ee665 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/FieldEditorHelper.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/FieldEditorHelper.java @@ -18,6 +18,7 @@ import com.ridgebotics.ridgescout.types.input.NumberType; import com.ridgebotics.ridgescout.types.input.SliderType; import com.ridgebotics.ridgescout.types.input.TallyType; import com.ridgebotics.ridgescout.types.input.TextType; +import com.ridgebotics.ridgescout.types.input.ToggleType; import com.ridgebotics.ridgescout.utility.AlertManager; import java.lang.reflect.Field; @@ -29,7 +30,8 @@ public class FieldEditorHelper { paramNumber, paramString, paramStringArray, - paramNumberArray + paramNumberArray, + paramBoolean } public static class parameterType { @@ -64,6 +66,15 @@ public class FieldEditorHelper { } } + public static class paramBoolean extends parameterType{ + public boolean val; + public paramBoolean(String name, boolean val){ + this.name = name + " (Boolean)"; + this.val = val; + this.id = parameterTypeEnum.paramBoolean; + } + } + // public static class paramNumberArray extends parameterType{ // public int[] val; // public paramNumberArray(String name, int[] val){ @@ -113,6 +124,12 @@ public class FieldEditorHelper { new paramNumber("Default Y", 0) }; + public static final parameterType[] defaultToggleParam = new parameterType[]{ + new paramString("Name", "New Toggle"), + new paramString("Description", ""), + new paramBoolean("Default true or false",true) + }; + private static parameterType[] getSliderParams(SliderType s){ return new parameterType[]{ @@ -173,6 +190,13 @@ public class FieldEditorHelper { new paramNumber("Default Y", ((int[]) s.default_value)[1]) }; } + private static parameterType[] getToggleParams(ToggleType s){ + return new parameterType[]{ + new paramString("Name", s.name), + new paramString("Description", s.description), + new paramBoolean("Default true or false", (boolean) s.default_value) + }; + } @@ -224,6 +248,12 @@ public class FieldEditorHelper { }; } + public static void setToggleParam(ToggleType s, parameterType[] types){ + s.name = ((paramString) types[0]).val; + s.description = ((paramString) types[1]).val; + s.default_value = ((paramBoolean) types[2]).val; + } + private static void setInputParameter(FieldType t, parameterType[] types){ switch (t.getInputType()){ @@ -248,6 +278,9 @@ public class FieldEditorHelper { case FIELDPOS: setFieldPosParam((FieldposType) t, types); break; + case TOGGLE: + setToggleParam((ToggleType) t, types); + break; } } @@ -269,6 +302,8 @@ public class FieldEditorHelper { return getCheckboxParam((CheckboxType) t); case FIELDPOS: return getFieldPosParam((FieldposType) t); + case TOGGLE: + return getToggleParams((ToggleType) t); } return new parameterType[]{}; } @@ -305,6 +340,16 @@ public class FieldEditorHelper { )); return text; } + private static View createBooleanEdit(Context c, boolean value){ + EditText text = new EditText(c); + text.setText(value); + text.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + return text; + } + private static View createEdit(Context c, parameterType t){ switch (t.id){ @@ -384,6 +429,11 @@ public class FieldEditorHelper { fieldposType.UUID = UUID.randomUUID().toString(); setFieldPosParam(fieldposType, defaultFieldPosParam); return fieldposType; + case 7: + ToggleType toggleType = new ToggleType(); + toggleType.UUID = UUID.randomUUID().toString(); + setToggleParam(toggleType, defaultToggleParam); + return toggleType; } return null; }