From 28a5d909a9fa78b0cf4e02e0083e658d3ffe92a0 Mon Sep 17 00:00:00 2001 From: astatin3 Date: Sat, 29 Jun 2024 02:52:17 -0600 Subject: [PATCH] Make scouting data fields actually work well. --- README.md | 4 +- .../scoutingData/ScoutingVersion.java | 131 +++++++++++++++++- .../scoutingapp2025/scoutingData/fields.java | 7 +- .../ui/scouting/ScoutingDataView.java | 19 +++ .../ui/scouting/matchScoutingView.java | 111 ++++----------- .../ui/settings/settingsFragment.java | 2 +- 6 files changed, 182 insertions(+), 92 deletions(-) create mode 100644 app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/ScoutingDataView.java diff --git a/README.md b/README.md index d9a25db..bea41d6 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,13 @@ Ridgebotics 2025 scouting app in Android TODO: -- Clean up matchScoutingView class, and make it provide code for both pit and match scouting -- Separate the inputTypes classes into their own files, and integrate the some of the stuff from matchScoutingView to make the code cleaner. +- Copy matchScoutingView to create pitScoutingView - Make the file browser UI - Add white border around the datamatrix code to allow file transfer in dark mode - Fix the code scanning progress indicator - Make pit and match data field builder UIs. I don't want to have to keep editing a variable Also TODO: -- Copy matchScoutingView to create pitScoutingView - Add more types of data fields. - Make the "Search" menu - Make the "Compile" menu diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/ScoutingVersion.java b/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/ScoutingVersion.java index b66aba8..372abe7 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/ScoutingVersion.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/ScoutingVersion.java @@ -1,9 +1,28 @@ package com.astatin3.scoutingapp2025.scoutingData; +import android.app.slice.Slice; +import android.content.Context; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings; import com.astatin3.scoutingapp2025.utility.BuiltByteParser; import com.astatin3.scoutingapp2025.utility.ByteBuilder; +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 ScoutingVersion { public static final int slider_type_id = 255; @@ -34,6 +53,11 @@ public class ScoutingVersion { } public abstract byte[] encode() throws ByteBuilder.buildingException; public abstract void decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption; + + public abstract View createView(Context context, Function onUpdate); + public void setViewValue(dataType type){setViewValue(type.get());} + public abstract void setViewValue(Object value); + public abstract dataType getViewValue(); } // public class usernameType extends inputType { @@ -77,8 +101,37 @@ public class ScoutingVersion { min = (int) objects.get(2).get(); max = (int) objects.get(3).get(); } + + public Slider slider = null; + + public View createView(Context context, Function onUpdate){ + slider = new Slider(context); + setViewValue(default_value); + slider.setStepSize((float) 1 / max); + slider.addOnChangeListener(new Slider.OnChangeListener() { + @Override + public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) { + onUpdate.apply(getViewValue()); + } + }); + return slider; + + } + public void setViewValue(Object value) { + if(slider == null) return; + float slider_position = (float) ((int) value-min) / (max-min); + float step_size = (float) 1/max; + int round_position = Math.round(slider_position / step_size); + slider.setValue(round_position*step_size); + } + public dataType getViewValue(){ + if(slider == null) return null; + return new intType(name, min + (int) (slider.getValue() * (max-min))); + } } + + public class dropdownType extends inputType { public String[] text_options; public int get_byte_id() {return dropdownType;} @@ -105,6 +158,57 @@ public class ScoutingVersion { default_value = objects.get(1).get(); text_options = (String[]) objects.get(2).get(); } + + public PowerSpinnerView dropdown = null; + + public View createView(Context context, Function onUpdate){ + dropdown = new PowerSpinnerView(context); + + List iconSpinnerItems = new ArrayList<>(); + for(int i = 0; i < text_options.length; i++){ + iconSpinnerItems.add(new IconSpinnerItem(text_options[i])); + } + IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(dropdown); + dropdown.setSpinnerAdapter(iconSpinnerAdapter); + dropdown.setItems(iconSpinnerItems); + + dropdown.selectItemByIndex((int) default_value); + + dropdown.setPadding(10,10,10,10); + dropdown.setBackgroundColor(0xf0000000); + dropdown.setTextSize(15); + dropdown.setArrowGravity(SpinnerGravity.END); + dropdown.setArrowPadding(8); + dropdown.setSpinnerItemHeight(46); + dropdown.setSpinnerPopupElevation(14); + + + dropdown.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener() { + @Override + public void onItemSelected(int oldIndex, @Nullable IconSpinnerItem oldItem, int newIndex, + IconSpinnerItem newItem) { + onUpdate.apply(getViewValue()); + } + }); + +// dropdown.setLifecycleOwner(context.life); +// slider.addOnChangeListener(new Slider.OnChangeListener() { +// @Override +// public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) { +// onUpdate.apply(getViewValue()); +// } +// }); + return dropdown; + + }; + public void setViewValue(Object value) { + if(dropdown == null) return; + dropdown.selectItemByIndex((int) value); + } + public dataType getViewValue(){ + if(dropdown == null) return null; + return new intType(name, dropdown.getSelectedIndex()); + } } public class notesType extends inputType { @@ -129,6 +233,30 @@ public class ScoutingVersion { name = (String) objects.get(0).get(); default_value = objects.get(1).get(); } + + public EditText text = null; + + public View createView(Context context, Function onUpdate){ + text = new EditText(context); + text.setText((String)default_value); + text.addTextChangedListener(new TextWatcher() { + public void afterTextChanged(Editable s) { + onUpdate.apply(getViewValue()); } + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void onTextChanged(CharSequence s, int start, int before, int count) {} + }); + + return text; + + }; + public void setViewValue(Object value) { + if(text == null) return; + text.setText((String) value); + } + public dataType getViewValue(){ + if(text == null) return null; + return new stringType(name, text.getText().toString()); + } } @@ -259,7 +387,6 @@ public class ScoutingVersion { new_values[i] = create_transfer((createTransferType) tv); continue; } - System.out.println(new_values[i]); } this.array = new_values; version++; @@ -297,14 +424,12 @@ public class ScoutingVersion { private dataType create_transfer(createTransferType tv){ inputType it = get_input_type_by_name(version+1, tv.name); -// System.out.println(tv.name); switch (it.getValueType()){ case NUM: return new intType(it.name, (int) it.default_value); case STRING: return new stringType(it.name, (String) it.default_value); } - System.out.println(2); return null; } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/fields.java b/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/fields.java index 872a373..c1aa577 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/fields.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/scoutingData/fields.java @@ -18,7 +18,12 @@ public class fields { sv.new notesType("notes", ""), },{ sv.new sliderType("How good is robot", 5, 0, 10), - sv.new sliderType("Test", 1, 0, 10), + sv.new sliderType("Test", 128, 64, 256), + sv.new notesType("notes", ""), + },{ + sv.new sliderType("How good is robot", 5, 0, 10), + sv.new sliderType("Test", 128, 64, 256), + sv.new dropdownType("test-dropdown", new String[]{"Test1", "test2", "Three"}, 1), sv.new notesType("notes", ""), } }; diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/ScoutingDataView.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/ScoutingDataView.java new file mode 100644 index 0000000..405659f --- /dev/null +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/ScoutingDataView.java @@ -0,0 +1,19 @@ +package com.astatin3.scoutingapp2025.ui.scouting; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.constraintlayout.widget.ConstraintLayout; + +public class ScoutingDataView extends ConstraintLayout { + public ScoutingDataView(Context context) { + super(context); + } + public ScoutingDataView(Context context, AttributeSet attributeSet){ + super(context, attributeSet); + } + + public void load(String fieldsFilename){ + + } +} diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/matchScoutingView.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/matchScoutingView.java index 9838161..78afb57 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/matchScoutingView.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/scouting/matchScoutingView.java @@ -23,6 +23,7 @@ import com.google.android.material.slider.Slider; import com.skydoves.powerspinner.PowerSpinnerView; import java.util.ArrayList; +import java.util.function.Function; public class matchScoutingView extends ConstraintLayout { public matchScoutingView(Context context) { @@ -32,8 +33,8 @@ public class matchScoutingView extends ConstraintLayout { super(context, attributeSet); } - int unsaved_color = 0x60ff0000; - int saved_color = 0x6000ff00; + private static final int unsaved_color = 0x60ff0000; + private static final int saved_color = 0x6000ff00; FragmentScoutingBinding binding; String alliance_position; @@ -131,7 +132,7 @@ public class matchScoutingView extends ConstraintLayout { binding.MatchScoutArea.removeView(views.get(i)); } - views = new ArrayList<>(); +// views = new ArrayList<>(); create_fields(); update_scouting_data(); @@ -141,46 +142,28 @@ public class matchScoutingView extends ConstraintLayout { private void create_fields(){ + if(asm.isRunning){ + asm.stop(); + } + for(int i = 0 ; i < latest_values.length; i++) { TextView tv = new TextView(getContext()); tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + tv.setText(latest_values[i].name); tv.setTextSize(24); binding.MatchScoutArea.addView(tv); -// views.add(tv); - switch (latest_values[i].getInputType()) { - case SLIDER: - ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i]; -// dataTypes.add() - tv.setText(sliderType.name); + View v = latest_values[i].createView(getContext(), new Function() { + @Override + public Integer apply(ScoutingVersion.dataType dataType) { +// edited = true; + if(asm.isRunning) + update_asm(); + return 0; + } + }); - Slider slider = new Slider(getContext()); - - slider.setStepSize((float) 1 / sliderType.max); - slider.setValue((int) sliderType.default_value / (float) sliderType.max); - - slider.addOnChangeListener(new Slider.OnChangeListener() { - @Override - public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) { - System.out.println(value * sliderType.max); - update_asm(); - } - }); - - binding.MatchScoutArea.addView(slider); - views.add(slider); - break; - case DROPDOWN: - ScoutingVersion.dropdownType dropdownType = (ScoutingVersion.dropdownType) latest_values[i]; - tv.setText(dropdownType.name); - views.add(new PowerSpinnerView(getContext())); - break; - case NOTES_INPUT: - ScoutingVersion.notesType notesType = (ScoutingVersion.notesType) latest_values[i]; - tv.setText(notesType.name); - views.add(new EditText(getContext())); - break; - } + binding.MatchScoutArea.addView(v); } } @@ -194,8 +177,6 @@ public class matchScoutingView extends ConstraintLayout { binding.matchnum.setText(String.valueOf(cur_match_num+1)); - System.out.println(cur_match_num); - if(cur_match_num <= 0){ binding.backButton.setVisibility(View.GONE); }else{ @@ -275,14 +256,9 @@ public class matchScoutingView extends ConstraintLayout { public void default_fields(){ - for(int i = 0; i < views.size(); i++){ - if(views.get(i).getClass() == Slider.class){ - ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i]; - ((Slider) views.get(i)).setValue((int) sliderType.default_value / (float) sliderType.max); - } -// } else if (views.get(i).getClass() == .class) { -// -// } + for(int i = 0; i < latest_values.length; i++){ + ScoutingVersion.inputType input = latest_values[i]; + input.setViewValue(input.default_value); } } @@ -293,27 +269,10 @@ public class matchScoutingView extends ConstraintLayout { ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, values, transferValues); ScoutingVersion.dataType[] types = psdr.data.array; - for(int i = 0; i < views.size(); i++){ - - View view = views.get(i); - Class c = view.getClass(); - - if(c == Slider.class){ - ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i]; - ((Slider) view).setValue((float) (sliderType.min + (int) types[i].get()) / (sliderType.max-sliderType.min)); - - -// types[i] = fields.sv.new intType(latest_values[i].name, (int) ((Slider) view).getValue()); - - - } else if (c == PowerSpinnerView.class) { -// types[i] = fields.sv.new intType(latest_values[i].name, 0); - } else if (c == EditText.class) { -// types[i] = fields.sv.new stringType(latest_values[i].name, "Test String"); - } + for(int i = 0; i < latest_values.length; i++){ +// types[i] = latest_values[i].getViewValue(); + latest_values[i].setViewValue(types[i]); } - -// System.out.println(ScoutingDataWriter.save(values.length, username, filename, types)); } @@ -322,26 +281,10 @@ public class matchScoutingView extends ConstraintLayout { ScoutingVersion.dataType[] types = new ScoutingVersion.dataType[latest_values.length]; - for(int i = 0; i < views.size(); i++){ - - View view = views.get(i); - Class c = view.getClass(); - - if(c == Slider.class){ - ScoutingVersion.sliderType sliderType = (ScoutingVersion.sliderType) latest_values[i]; - - types[i] = fields.sv.new intType(latest_values[i].name, - sliderType.min + (int)(((Slider) view).getValue() * (sliderType.max-sliderType.min))); - - - } else if (c == PowerSpinnerView.class) { - types[i] = fields.sv.new intType(latest_values[i].name, 0); - } else if (c == EditText.class) { - types[i] = fields.sv.new stringType(latest_values[i].name, "Test String"); - } + for(int i = 0; i < latest_values.length; i++){ + types[i] = latest_values[i].getViewValue(); } - System.out.println(types.length); System.out.println(ScoutingDataWriter.save(values.length-1, username, filename, types)); } } diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/settings/settingsFragment.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/settings/settingsFragment.java index b86e2d5..f5ac525 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/settings/settingsFragment.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/settings/settingsFragment.java @@ -88,7 +88,7 @@ public class settingsFragment extends Fragment { IconSpinnerAdapter iconSpinnerAdapter = new IconSpinnerAdapter(spinnerView); spinnerView.setSpinnerAdapter(iconSpinnerAdapter); spinnerView.setItems(iconSpinnerItems); - spinnerView.setLifecycleOwner(this); +// spinnerView.setLifecycleOwner(this); if(!iconSpinnerItems.isEmpty() && target_index != -1){ spinnerView.selectItemByIndex(target_index);