mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-09 08:38:03 -06:00
Add tally counter
This commit is contained in:
@@ -2,9 +2,11 @@ package com.astatin3.scoutingapp2025.scoutingData;
|
||||
|
||||
import com.astatin3.scoutingapp2025.types.input.dropdownType;
|
||||
import com.astatin3.scoutingapp2025.types.input.inputType;
|
||||
import com.astatin3.scoutingapp2025.types.input.tallyType;
|
||||
import com.astatin3.scoutingapp2025.types.input.textType;
|
||||
import com.astatin3.scoutingapp2025.types.input.sliderType;
|
||||
import com.astatin3.scoutingapp2025.types.input.textType;
|
||||
import com.astatin3.scoutingapp2025.ui.scouting.TallyCounterView;
|
||||
import com.astatin3.scoutingapp2025.utility.AlertManager;
|
||||
import com.astatin3.scoutingapp2025.utility.fileEditor;
|
||||
import com.astatin3.scoutingapp2025.utility.BuiltByteParser;
|
||||
@@ -31,7 +33,12 @@ public class fields {
|
||||
new sliderType("Test", 128, 64, 256),
|
||||
new dropdownType("test-dropdown", new String[]{"Test1", "test2", "Three"}, 1),
|
||||
new textType("notes", "<no-notes>"),
|
||||
}
|
||||
},{
|
||||
new tallyType("Test Tally", 0),
|
||||
new sliderType("Test2", 30, 25, 50),
|
||||
new dropdownType("test-dropdown", new String[]{"Test1", "test2", "Three"}, 1),
|
||||
new textType("notes", "<no-notes>"),
|
||||
}
|
||||
};
|
||||
|
||||
public static final inputType[][] default_pit_fields = new inputType[][] {
|
||||
@@ -111,11 +118,13 @@ public class fields {
|
||||
case inputType.notesType:
|
||||
t = new textType();
|
||||
break;
|
||||
case inputType.tallyType:
|
||||
t = new tallyType();
|
||||
break;
|
||||
}
|
||||
|
||||
t.decode((byte[]) obj.get());
|
||||
output[i] = t
|
||||
;
|
||||
output[i] = t;
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -17,11 +17,13 @@ public abstract class inputType {
|
||||
public static final int slider_type_id = 255;
|
||||
public static final int dropdownType = 254;
|
||||
public static final int notesType = 253;
|
||||
public static final int tallyType = 252;
|
||||
public enum inputTypes {
|
||||
// USERNAME,
|
||||
SLIDER,
|
||||
DROPDOWN,
|
||||
NOTES_INPUT
|
||||
NOTES_INPUT,
|
||||
TALLY
|
||||
}
|
||||
public String name;
|
||||
public Object default_value;
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
package com.astatin3.scoutingapp2025.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.astatin3.scoutingapp2025.types.data.dataType;
|
||||
import com.astatin3.scoutingapp2025.types.data.intType;
|
||||
import com.astatin3.scoutingapp2025.ui.scouting.TallyCounterView;
|
||||
import com.astatin3.scoutingapp2025.utility.BuiltByteParser;
|
||||
import com.astatin3.scoutingapp2025.utility.ByteBuilder;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.charts.PieChart;
|
||||
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.github.mikephil.charting.data.PieData;
|
||||
import com.github.mikephil.charting.data.PieDataSet;
|
||||
import com.github.mikephil.charting.data.PieEntry;
|
||||
import com.google.android.material.slider.Slider;
|
||||
import com.skydoves.powerspinner.IconSpinnerAdapter;
|
||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
||||
import com.skydoves.powerspinner.PowerSpinnerView;
|
||||
import com.skydoves.powerspinner.SpinnerGravity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class tallyType extends inputType {
|
||||
public int get_byte_id() {return tallyType;}
|
||||
public inputTypes getInputType(){return inputTypes.TALLY;}
|
||||
public dataType.valueTypes getValueType(){return dataType.valueTypes.NUM;}
|
||||
public Object get_fallback_value(){return 0;}
|
||||
public tallyType(){};
|
||||
public String get_type_name(){return "Dropdown";}
|
||||
public tallyType(String name, int default_value){
|
||||
super(name);
|
||||
this.default_value = default_value+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] encode() throws ByteBuilder.buildingException {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
bb.addString(name);
|
||||
bb.addInt((int)default_value);
|
||||
return bb.build();
|
||||
}
|
||||
public void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
|
||||
name = (String) objects.get(0).get();
|
||||
default_value = objects.get(1).get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public TallyCounterView tally = null;
|
||||
|
||||
public View createView(Context context, Function<dataType, Integer> 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;
|
||||
System.out.println(value);
|
||||
if(((int)value) == 0){
|
||||
nullify();
|
||||
return;
|
||||
}
|
||||
|
||||
isBlank = false;
|
||||
tally.setVisibility(View.VISIBLE);
|
||||
tally.setValue((int)value-1);
|
||||
}
|
||||
public void nullify(){
|
||||
isBlank = true;
|
||||
tally.setVisibility(View.GONE);
|
||||
}
|
||||
public dataType getViewValue(){
|
||||
if(tally == null) return null;
|
||||
if(tally.getVisibility() == View.GONE) return new intType(name, 0);
|
||||
return new intType(name, tally.getValue()+1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_individual_view(LinearLayout parent, dataType data){
|
||||
if((int)data.get() == 0) 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()-1));
|
||||
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 += Math.pow((float) value - mean, 2);
|
||||
}
|
||||
return (float) Math.sqrt(sum / (data.length - 1));
|
||||
}
|
||||
|
||||
private static List<Entry> generateNormalDistribution(float mean, float stdDev, int count, int scale) {
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
float x = i;
|
||||
float y = (float) ((1 / (stdDev * Math.sqrt(2 * Math.PI)))
|
||||
* Math.exp(-0.5 * Math.pow((x - mean) / stdDev, 2)));
|
||||
entries.add(new Entry(x, y*scale)); // Scale y for visibility
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static int findMin(dataType[] data){
|
||||
int min = (int)data[0].get()-1;
|
||||
for(int i = 1; i < data.length; i++)
|
||||
if((int)data[i].get()-1 < min)
|
||||
min = (int)data[i].get()-1;
|
||||
return min;
|
||||
}
|
||||
|
||||
private static int findMax(dataType[] data){
|
||||
int max = (int)data[0].get()-1;
|
||||
for(int i = 1; i < data.length; i++)
|
||||
if((int)data[i].get()-1 > max)
|
||||
max = (int)data[i].get()-1;
|
||||
return max;
|
||||
}
|
||||
|
||||
public void add_compiled_view(LinearLayout parent, dataType[] 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((int) data[i].get() != intType.nulval)
|
||||
values[(int) data[i].get()-min-1]++;
|
||||
|
||||
|
||||
ArrayList<Integer> 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()-1);
|
||||
|
||||
int[] mean_vals = mean_temp.stream().mapToInt(Integer::intValue).toArray();
|
||||
|
||||
List<Entry> 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(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
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<Entry> normalDistEntries = generateNormalDistribution(mean-min, stdDev, max-min+1, (max-min)/data.length);
|
||||
|
||||
|
||||
LineDataSet normalDistSet = new LineDataSet(normalDistEntries, "Normal Distribution");
|
||||
normalDistSet.setColor(Color.RED);
|
||||
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(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void add_history_view(LinearLayout parent, dataType[] 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);
|
||||
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
for (int i = 0; i < data.length; i++){
|
||||
if(data[i] == null) continue;
|
||||
|
||||
entries.add(new Entry(i, (float)(int) data[i].get()-1));
|
||||
}
|
||||
|
||||
|
||||
LineDataSet dataSet = new LineDataSet(entries, name);
|
||||
dataSet.setColor(Color.BLUE);
|
||||
dataSet.setValueTextColor(Color.BLACK);
|
||||
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(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
|
||||
chart.getAxisLeft().setAxisMinimum(min);
|
||||
chart.getAxisLeft().setAxisMaximum(max);
|
||||
|
||||
chart.getAxisRight().setAxisMinimum(min);
|
||||
chart.getAxisRight().setAxisMaximum(max);
|
||||
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -178,8 +178,8 @@ public class MatchScoutingFragment extends Fragment {
|
||||
// boolean blank = !latest_values[fi].getViewValue().isNull();
|
||||
|
||||
// System.out.println(blank);
|
||||
|
||||
asm.update();
|
||||
if(asm.isRunning)
|
||||
update_asm();
|
||||
|
||||
if(!DataManager.match_latest_values[fi].isBlank){
|
||||
tv.setBackgroundColor(0xffff0000);
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.astatin3.scoutingapp2025.ui.scouting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.astatin3.scoutingapp2025.R;
|
||||
|
||||
public class TallyCounterView extends LinearLayout {
|
||||
private int count = 0;
|
||||
private TextView countDisplay;
|
||||
private Button minusButton;
|
||||
private Button plusButton;
|
||||
private OnCountChangedListener onCountChangedListener;
|
||||
|
||||
public interface OnCountChangedListener {
|
||||
void onCountChanged(int newCount);
|
||||
}
|
||||
|
||||
public TallyCounterView(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public TallyCounterView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public TallyCounterView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.view_tally_counter, this, true);
|
||||
|
||||
countDisplay = findViewById(R.id.count_display);
|
||||
minusButton = findViewById(R.id.minus_button);
|
||||
plusButton = findViewById(R.id.plus_button);
|
||||
|
||||
updateDisplay();
|
||||
|
||||
minusButton.setOnClickListener(v -> {
|
||||
if(count > 0) {
|
||||
count--;
|
||||
updateDisplay();
|
||||
}
|
||||
});
|
||||
|
||||
plusButton.setOnClickListener(v -> {
|
||||
count++;
|
||||
updateDisplay();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateDisplay() {
|
||||
countDisplay.setText(String.valueOf(count));
|
||||
if (onCountChangedListener != null) {
|
||||
onCountChangedListener.onCountChanged(count);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
count = value;
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setOnCountChangedListener(OnCountChangedListener listener) {
|
||||
this.onCountChangedListener = listener;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user