Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79e8e7cbfc |
@@ -7,27 +7,17 @@
|
|||||||
|
|
||||||
[**Read the wiki**](https://github.com/Team4388/ScoutingApp2025/wiki)
|
[**Read the wiki**](https://github.com/Team4388/ScoutingApp2025/wiki)
|
||||||
|
|
||||||
[**Test Data**](https://github.com/Team4388/ScoutingApp2025/blob/main/2024week0-1728149849985.scoutbundle)
|
#### Features
|
||||||
|
|
||||||
#### Here is an overview of the main features currently included in the app:
|
|
||||||
- This project is written for Android! No need for some kind of janky laptop charging setup.
|
- This project is written for Android! No need for some kind of janky laptop charging setup.
|
||||||
- Similar to ScoutingPASS, many different types of fields can be used to collect data.
|
- Similar to ScoutingPASS, there are many diffrent types of fields that can be used to collect data.
|
||||||
- The app is designed to handle updates to the fields on the fly, without losing any data!
|
- The app is designed to handle updates to the fields on the fly, without loosing any data!
|
||||||
- Unlike other scouting solutions, scouters can disable any field they did not measure, and disabled fields will not be included in any calculations.
|
- Unlike other scouting solutions, scouters can disable any field they did not measure, and disabled fields will not be included in any calculations.
|
||||||
- Dynamic displays based on the different fields.
|
- Dynamic displays based off of the diffrent fields.
|
||||||
- Data transfer including 2D codes, Bluetooth, and File Bundle.
|
- Data transfer including 2D codes, Bluetooth, and File Bundle.
|
||||||
- Exporting using CSV.
|
- Exporting using CSV.
|
||||||
- Deployment on F-Droid
|
- Deployment on F-Droid
|
||||||
- Data cloud sync using an FTP server
|
- Data cloud sync using an FTP server
|
||||||
|
|
||||||
#### Things that are yet to be implemented:
|
|
||||||
- A page that lets users cross-compare scouting data between teams. (Compare)
|
|
||||||
|
|
||||||
#### Things that may or may not be implemented:
|
|
||||||
- Statbotics integration
|
|
||||||
- Scout error estimation using OPR-like calculation
|
|
||||||
- - Would most likely require Statbotics
|
|
||||||
https://www.thebluealliance.com/avatars
|
|
||||||
### Screenshots
|
### Screenshots
|
||||||
|Match scouting interface|Field editor|Teams data viewer|
|
|Match scouting interface|Field editor|Teams data viewer|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ android {
|
|||||||
dependenciesInfo {
|
dependenciesInfo {
|
||||||
// Disables dependency metadata when building APKs.
|
// Disables dependency metadata when building APKs.
|
||||||
includeInApk = false
|
includeInApk = false
|
||||||
// Disables dependency metadata when building Android App Bundles.5
|
// Disables dependency metadata when building Android App Bundles.
|
||||||
includeInBundle = false
|
includeInBundle = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ android {
|
|||||||
applicationId = "com.ridgebotics.ridgescout"
|
applicationId = "com.ridgebotics.ridgescout"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 15 // **IMPORTANT** Increment this before releasing on github
|
versionCode = 11 // **IMPORTANT** Increment this before releasing on github
|
||||||
versionName = "3.1"// **IMPORTANT** Change this before releasing on github (<Year num since 2024>.<Update Version>)
|
versionName = "1.4"// **IMPORTANT** Change this before releasing on github (<Year num since 2024>.<Update Version>)
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,13 +47,11 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
// Load default match fields
|
// Load default match fields
|
||||||
if(!FileEditor.fileExist(Fields.matchFieldsFilename)){
|
if(!FileEditor.fileExist(Fields.matchFieldsFilename)){
|
||||||
Fields.save(Fields.matchFieldsFilename, Fields.default_match_fields);
|
Fields.save(Fields.matchFieldsFilename, Fields.default_match_fields);
|
||||||
FileEditor.toTheArchaicPeriod(Fields.matchFieldsFilename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load default pit fields
|
// Load default pit fields
|
||||||
if(!FileEditor.fileExist(Fields.pitsFieldsFilename)){
|
if(!FileEditor.fileExist(Fields.pitsFieldsFilename)){
|
||||||
Fields.save(Fields.pitsFieldsFilename, Fields.default_pit_fields);
|
Fields.save(Fields.pitsFieldsFilename, Fields.default_pit_fields);
|
||||||
FileEditor.toTheArchaicPeriod(Fields.pitsFieldsFilename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get time zone for FTP file transfer
|
// get time zone for FTP file transfer
|
||||||
|
|||||||
@@ -30,7 +30,36 @@ public class Fields {
|
|||||||
|
|
||||||
public static final FieldType[][] default_match_fields = new FieldType[][] {
|
public static final FieldType[][] default_match_fields = new FieldType[][] {
|
||||||
{
|
{
|
||||||
new FieldposType(uuid(),"Auto start pos", "Where does the robot start its auto?", new int[]{0,0})
|
new FieldposType(uuid(),"Auto start pos", "Where does the robot start its auto?", FieldposType.DEFAULT_FIELD_IMAGE, new int[]{0,0}),
|
||||||
|
|
||||||
|
new TallyType(uuid(),"Auto L4 Coral", "How many coral did this robot score in L4 during auto?", 0),
|
||||||
|
new TallyType(uuid(),"Auto L3 Coral", "How many coral did this robot score in L3 during auto?", 0),
|
||||||
|
new TallyType(uuid(),"Auto L2 Coral", "How many coral did this robot score in L2 during auto?", 0),
|
||||||
|
new TallyType(uuid(),"Auto L1/Trough Coral", "How many coral did this robot score in L1 during auto?", 0),
|
||||||
|
new TallyType(uuid(),"Auto Processor Algae", "How many algae did this robot score in the Barge during auto?", 0),
|
||||||
|
new TallyType(uuid(),"Auto Barge Algae", "How many algae did this robot score in the Barge during auto?", 0),
|
||||||
|
|
||||||
|
new DropdownType(uuid(),"Auto Quality", "How did the robot drive during auto?", new String[]{"Smooth", "Jittery"}, 0),
|
||||||
|
new TextType(uuid(),"Auto Comments", "Anything interesting about auto", ""),
|
||||||
|
|
||||||
|
new TallyType(uuid(),"Teleop L4 Coral", "How many coral did this robot score in L4 during teleop?", 0),
|
||||||
|
new TallyType(uuid(),"Teleop L3 Coral", "How many coral did this robot score in L3 during teleop?", 0),
|
||||||
|
new TallyType(uuid(),"Teleop L2 Coral", "How many coral did this robot score in L2 during teleop?", 0),
|
||||||
|
new TallyType(uuid(),"Teleop L1 Coral", "How many coral did this robot score in L1 during teleop?", 0),
|
||||||
|
new TallyType(uuid(),"Teleop Processor Algae", "How many algae did this robot score in the Barge during teleop?", 0),
|
||||||
|
new TallyType(uuid(),"Teleop Barge Algae", "How many algae did this robot score in the Barge during teleop?", 0),
|
||||||
|
|
||||||
|
new CheckboxType(uuid(),"Upper Algae Removal", "Did the robot remove upper Algae?", 0),
|
||||||
|
new CheckboxType(uuid(),"Lower Algae Removal", "Did the robot remove lower Algae?", 0),
|
||||||
|
|
||||||
|
new DropdownType(uuid(),"Teleop Quality", "How did the robot drive during Teleop?", new String[]{"Smooth", "Jittery"}, 0),
|
||||||
|
new TextType(uuid(),"Teleop Comments", "Anything interesting about Teleop", ""),
|
||||||
|
|
||||||
|
new DropdownType(uuid(),"Climb State", "What was the final condition of the robot?", new String[]{"Nothing", "Continued Cycling", "Park", "Attempted Shallow", "Shallow", "Attempted Deep", "Deep"}, 0),
|
||||||
|
|
||||||
|
new DropdownType(uuid(),"Robot Condition", "Was anything broken?", new String[]{"Everything was working", "Something was maybe broken", "Something was broken", "Robot was disabled for part of the match", "Missing robot"}, 0),
|
||||||
|
|
||||||
|
new TextType(uuid(),"Other Comments", "Any other comments you have", "")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,6 +69,14 @@ public class Fields {
|
|||||||
new DropdownType(uuid(),"Intake type", "What type of intake does this team have?", new String[]{"Ground only", "Player Station only", "Both", "Other, Info in comments"}, 0),
|
new DropdownType(uuid(),"Intake type", "What type of intake does this team have?", new String[]{"Ground only", "Player Station only", "Both", "Other, Info in comments"}, 0),
|
||||||
new DropdownType(uuid(),"Intake Consistency", "How consistent is the robot at intakeing?", new String[]{"Does not work", "Worked a few times during testing", "Works most of the time", "Fails sometimes", "Never fails"}, 0),
|
new DropdownType(uuid(),"Intake Consistency", "How consistent is the robot at intakeing?", new String[]{"Does not work", "Worked a few times during testing", "Works most of the time", "Fails sometimes", "Never fails"}, 0),
|
||||||
|
|
||||||
|
new DropdownType(uuid(),"Score Area", "What does this robot score?", new String[]{"Only Algae", "Mostly Algae", "Both", "Mostly Coral", "Only Coral"}, 0),
|
||||||
|
|
||||||
|
new CheckboxType(uuid(),"L4 Scoring", "Will the robot score in Layer 4?", 0),
|
||||||
|
new CheckboxType(uuid(),"L3 Scoring", "Will the robot score in Layer 3?", 0),
|
||||||
|
new CheckboxType(uuid(),"L2 Scoring", "Will the robot score in Layer 3?", 0),
|
||||||
|
new CheckboxType(uuid(),"L1/Trough Scoring", "Will the robot score in Layer 1?", 0),
|
||||||
|
new CheckboxType(uuid(),"Processor Scoring", "Will the robot score in the Processor?", 0),
|
||||||
|
new CheckboxType(uuid(),"Barge Scoring", "Will the robot score algae in the Barge?", 0),
|
||||||
new DropdownType(uuid(),"Scoring Consistency", "How consistent is the robot at Scoring?", new String[]{"Does not work", "Worked a few times during testing", "Works most of the time", "Fails sometimes", "Never fails"}, 0),
|
new DropdownType(uuid(),"Scoring Consistency", "How consistent is the robot at Scoring?", new String[]{"Does not work", "Worked a few times during testing", "Works most of the time", "Fails sometimes", "Never fails"}, 0),
|
||||||
|
|
||||||
new TextType(uuid(),"Auto Capability", "What autos does this team have?", ""),
|
new TextType(uuid(),"Auto Capability", "What autos does this team have?", ""),
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class ScoutingArray {
|
|||||||
continue;
|
continue;
|
||||||
case CREATE:
|
case CREATE:
|
||||||
new_values[i] = create_transfer((CreateTransferType) tv);
|
new_values[i] = create_transfer((CreateTransferType) tv);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.array = new_values;
|
this.array = new_values;
|
||||||
@@ -71,6 +72,12 @@ public class ScoutingArray {
|
|||||||
return get_data_type_by_UUID(tv.UUID);
|
return get_data_type_by_UUID(tv.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private dataType rename_transfer(renameTransferType tv){
|
||||||
|
// dataType dt = get_data_type_by_name(tv.name);
|
||||||
|
// dt.name = tv.new_name;
|
||||||
|
// return dt;
|
||||||
|
// }
|
||||||
|
|
||||||
private RawDataType create_transfer(CreateTransferType tv){
|
private RawDataType create_transfer(CreateTransferType tv){
|
||||||
FieldType it = get_input_type_by_UUID(version+1, tv.UUID);
|
FieldType it = get_input_type_by_UUID(version+1, tv.UUID);
|
||||||
switch (it.getValueType()){
|
switch (it.getValueType()){
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ public class ScoutingFile {
|
|||||||
ByteBuilder bb = new ByteBuilder()
|
ByteBuilder bb = new ByteBuilder()
|
||||||
.addString(filename);
|
.addString(filename);
|
||||||
|
|
||||||
|
// byte[] data = Objects.requireNonNull(fileEditor.readFile(filename));
|
||||||
|
|
||||||
|
// for(int i = 0; i < data.length / 65535; i++){
|
||||||
|
// bb.addRaw(255, fileEditor.getByteBlock(data, i*65535, (i+1)*65535));
|
||||||
|
// }
|
||||||
|
|
||||||
bb.addRaw(255, Objects.requireNonNull(FileEditor.readFile(filename)));
|
bb.addRaw(255, Objects.requireNonNull(FileEditor.readFile(filename)));
|
||||||
|
|
||||||
return bb.build();
|
return bb.build();
|
||||||
|
|||||||
@@ -16,14 +16,11 @@ import java.util.stream.IntStream;
|
|||||||
// Class to contain data for an entire event.
|
// Class to contain data for an entire event.
|
||||||
// Easily encoded and decoded to binary format.
|
// Easily encoded and decoded to binary format.
|
||||||
public class frcEvent {
|
public class frcEvent {
|
||||||
|
public String eventCode;
|
||||||
// public static final int typecode = 254; Unused, no idea what this is
|
|
||||||
public String eventCode; //Current event code
|
|
||||||
public String name;
|
public String name;
|
||||||
public ArrayList<frcMatch> matches;
|
public ArrayList<frcMatch> matches;
|
||||||
public ArrayList<frcTeam> teams;
|
public ArrayList<frcTeam> teams;
|
||||||
|
|
||||||
// Turns frcEvent into raw data
|
|
||||||
public byte[] encode() {
|
public byte[] encode() {
|
||||||
try {
|
try {
|
||||||
ByteBuilder bb = new ByteBuilder()
|
ByteBuilder bb = new ByteBuilder()
|
||||||
@@ -49,7 +46,6 @@ public class frcEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Decodes the frcEvent
|
|
||||||
public static frcEvent decode(byte[] bytes) {
|
public static frcEvent decode(byte[] bytes) {
|
||||||
try {
|
try {
|
||||||
ArrayList<BuiltByteParser.parsedObject> objects =
|
ArrayList<BuiltByteParser.parsedObject> objects =
|
||||||
@@ -78,7 +74,6 @@ public class frcEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Generates text
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -207,7 +207,6 @@ public class CheckboxType extends FieldType {
|
|||||||
parent.addView(chart);
|
parent.addView(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public class DropdownType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Dropdown view
|
|
||||||
public void add_individual_view(LinearLayout parent, RawDataType data){
|
public void add_individual_view(LinearLayout parent, RawDataType data){
|
||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ public class DropdownType extends FieldType {
|
|||||||
.layout_match_wrap()
|
.layout_match_wrap()
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.size(18)
|
.size(18)
|
||||||
.align_left()
|
.align_center()
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ public class DropdownType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Generates N amount of colors, all opposite colors
|
|
||||||
private static int[] generateEquidistantColors(int N) {
|
private static int[] generateEquidistantColors(int N) {
|
||||||
int[] colors = new int[N];
|
int[] colors = new int[N];
|
||||||
float[] hsv = new float[3]; // Hue, Saturation, Value
|
float[] hsv = new float[3]; // Hue, Saturation, Value
|
||||||
@@ -138,7 +138,6 @@ public class DropdownType extends FieldType {
|
|||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turns the dropdown into a pie chart in the compiled view
|
|
||||||
public void add_compiled_view(LinearLayout parent, RawDataType[] data){
|
public void add_compiled_view(LinearLayout parent, RawDataType[] data){
|
||||||
PieChart chart = new PieChart(parent.getContext());
|
PieChart chart = new PieChart(parent.getContext());
|
||||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||||
@@ -172,7 +171,7 @@ public class DropdownType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Turns the dropdown into a line chart in the history view
|
|
||||||
public void add_history_view(LinearLayout parent, RawDataType[] data){
|
public void add_history_view(LinearLayout parent, RawDataType[] data){
|
||||||
LineChart chart = new LineChart(parent.getContext());
|
LineChart chart = new LineChart(parent.getContext());
|
||||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||||
@@ -239,7 +238,6 @@ public class DropdownType extends FieldType {
|
|||||||
parent.addView(chart);
|
parent.addView(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import com.github.mikephil.charting.components.Legend;
|
|||||||
import com.github.mikephil.charting.data.Entry;
|
import com.github.mikephil.charting.data.Entry;
|
||||||
import com.github.mikephil.charting.data.LineData;
|
import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
|
import com.ridgebotics.ridgescout.R;
|
||||||
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
||||||
import com.ridgebotics.ridgescout.types.data.IntArrType;
|
import com.ridgebotics.ridgescout.types.data.IntArrType;
|
||||||
import com.ridgebotics.ridgescout.ui.views.FieldPosView;
|
import com.ridgebotics.ridgescout.ui.views.FieldPosView;
|
||||||
@@ -31,14 +32,58 @@ import java.util.Map;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class FieldposType extends FieldType {
|
public class FieldposType extends FieldType {
|
||||||
|
public static final FieldImage DEFAULT_FIELD_IMAGE = FieldImage.F2025;
|
||||||
|
public enum FieldImage {
|
||||||
|
F2025(0, "2025", R.drawable.field_2025, R.drawable.field_2025_flipped),
|
||||||
|
F2025_analogous(1, "2025 - analogous", R.drawable.field_2025_analogous);
|
||||||
|
|
||||||
|
|
||||||
|
public int index, resId_normal, resId_flipped;
|
||||||
|
public String name;
|
||||||
|
public boolean flippable;
|
||||||
|
|
||||||
|
FieldImage(int index, String name, int resId) {
|
||||||
|
this.index = index;
|
||||||
|
this.name = name;
|
||||||
|
this.resId_normal = resId;
|
||||||
|
this.resId_flipped = resId;
|
||||||
|
this.flippable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldImage(int index, String name, int resId_normal, int resId_flipped) {
|
||||||
|
this.index = index;
|
||||||
|
this.name = name;
|
||||||
|
this.resId_normal = resId_normal;
|
||||||
|
this.resId_flipped = resId_flipped;
|
||||||
|
this.flippable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldImage from_index(int index) {
|
||||||
|
return FieldImage.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get_index() {
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldImage fieldImage;
|
||||||
|
|
||||||
|
|
||||||
public int get_byte_id() {return fieldposType;}
|
public int get_byte_id() {return fieldposType;}
|
||||||
public inputTypes getInputType(){return inputTypes.FIELDPOS;}
|
public inputTypes getInputType(){return inputTypes.FIELDPOS;}
|
||||||
public RawDataType.valueTypes getValueType(){return RawDataType.valueTypes.NUM;}
|
public RawDataType.valueTypes getValueType(){return RawDataType.valueTypes.NUM;}
|
||||||
public Object get_fallback_value(){return 0;}
|
public Object get_fallback_value(){return 0;}
|
||||||
public FieldposType(){}
|
public FieldposType(){}
|
||||||
public String get_type_name(){return "Field Pos";}
|
public String get_type_name(){return "Field Pos";}
|
||||||
public FieldposType(String UUID, String name, String description, int[] default_value){
|
public FieldposType(String UUID, String name, String description, FieldImage fieldImage, int[] default_value){
|
||||||
super(UUID, name, description);
|
super(UUID, name, description);
|
||||||
|
this.fieldImage = fieldImage;
|
||||||
this.default_value = default_value;
|
this.default_value = default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +92,14 @@ public class FieldposType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
public void encodeData(ByteBuilder bb) throws ByteBuilder.buildingException {
|
public void encodeData(ByteBuilder bb) throws ByteBuilder.buildingException {
|
||||||
|
bb.addInt(this.fieldImage.get_index());
|
||||||
bb.addIntArray((int[]) default_value);
|
bb.addIntArray((int[]) default_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeData(ArrayList<BuiltByteParser.parsedObject> objects) {
|
public void decodeData(ArrayList<BuiltByteParser.parsedObject> objects) {
|
||||||
default_value = objects.get(0).get();
|
fieldImage = FieldImage.from_index((int) objects.get(0).get());
|
||||||
|
default_value = objects.get(1).get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -65,6 +113,7 @@ public class FieldposType extends FieldType {
|
|||||||
onUpdate.apply(new IntArrType(name, pos));
|
onUpdate.apply(new IntArrType(name, pos));
|
||||||
});
|
});
|
||||||
setViewValue(default_value);
|
setViewValue(default_value);
|
||||||
|
field.setFieldImage(fieldImage);
|
||||||
return field;
|
return field;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -102,6 +151,7 @@ public class FieldposType extends FieldType {
|
|||||||
FieldPosView fp = new FieldPosView(parent.getContext());
|
FieldPosView fp = new FieldPosView(parent.getContext());
|
||||||
fp.setEnabled(false);
|
fp.setEnabled(false);
|
||||||
fp.setPos((int[]) data.get());
|
fp.setPos((int[]) data.get());
|
||||||
|
fp.setFieldImage(this.fieldImage);
|
||||||
|
|
||||||
parent.addView(fp);
|
parent.addView(fp);
|
||||||
}
|
}
|
||||||
@@ -113,54 +163,13 @@ public class FieldposType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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<Entry> generateNormalDistribution(float mean, float stdDev, int count, int scale) {
|
|
||||||
List<Entry> 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){
|
public void add_compiled_view(LinearLayout parent, RawDataType[] data){
|
||||||
MultiFieldPosView mfp = new MultiFieldPosView(parent.getContext());
|
MultiFieldPosView mfp = new MultiFieldPosView(parent.getContext());
|
||||||
for(int i = 0; i < data.length; i++){
|
for(int i = 0; i < data.length; i++){
|
||||||
if(data[i].isNull()) continue;
|
if(data[i].isNull()) continue;
|
||||||
mfp.addPos((int[]) data[i].get());
|
mfp.addPos((int[]) data[i].get());
|
||||||
}
|
}
|
||||||
|
mfp.setFieldImage(fieldImage);
|
||||||
parent.addView(mfp);
|
parent.addView(mfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +230,6 @@ public class FieldposType extends FieldType {
|
|||||||
parent.addView(chart);
|
parent.addView(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public class NumberType extends FieldType {
|
|||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
||||||
.layout_match_wrap()
|
.layout_match_wrap()
|
||||||
.align_left()
|
.align_center()
|
||||||
.size(24)
|
.size(24)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,6 @@ public class NumberType extends FieldType {
|
|||||||
parent.addView(chart);
|
parent.addView(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class TallyType extends FieldType {
|
|||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
||||||
.layout_match_wrap()
|
.layout_match_wrap()
|
||||||
.align_left()
|
.align_center()
|
||||||
.size(24)
|
.size(24)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class TextType extends FieldType {
|
|||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
parent.addView(new TextViewBuilder(parent.getContext(), (String) data.get())
|
parent.addView(new TextViewBuilder(parent.getContext(), (String) data.get())
|
||||||
.layout_match_wrap()
|
.layout_match_wrap()
|
||||||
.align_left()
|
.align_center()
|
||||||
.size(18)
|
.size(18)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,6 @@ public class TextType extends FieldType {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import static com.ridgebotics.ridgescout.utility.DataManager.pit_transferValues;
|
|||||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
@@ -222,18 +221,19 @@ public class TeamsFragment extends Fragment {
|
|||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[matchIndex], match_values, match_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[matchIndex], match_values, match_transferValues);
|
||||||
|
|
||||||
|
|
||||||
TextView title = new TextViewBuilder(getContext(),
|
binding.matchArea.addView(
|
||||||
"M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username)
|
new TextViewBuilder(getContext(), "M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username)
|
||||||
.align_center()
|
.align_center()
|
||||||
.size(30)
|
.size(30)
|
||||||
.padding(0, 0, 40, 5)
|
.padding(0,0,40,5)
|
||||||
.build();
|
.build()
|
||||||
title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
|
||||||
binding.matchArea.addView(title);
|
);
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < psda.data.array.length; i++) {
|
for (int i = 0; i < psda.data.array.length; i++) {
|
||||||
TextViewBuilder tv = new TextViewBuilder(getContext(), match_latest_values[i].name)
|
TextViewBuilder tv = new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||||
.align_left()
|
.align_center()
|
||||||
.size(25);
|
.size(25);
|
||||||
|
|
||||||
if (psda.data.array[i].isNull()) {
|
if (psda.data.array[i].isNull()) {
|
||||||
@@ -282,7 +282,6 @@ public class TeamsFragment extends Fragment {
|
|||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
if(data[i] != null)
|
if(data[i] != null)
|
||||||
match_latest_values[i].add_compiled_view(binding.matchArea, data[i]);
|
match_latest_values[i].add_compiled_view(binding.matchArea, data[i]);
|
||||||
}
|
}
|
||||||
@@ -308,13 +307,13 @@ public class TeamsFragment extends Fragment {
|
|||||||
|
|
||||||
for(int i = 0; i < match_latest_values.length; i++){
|
for(int i = 0; i < match_latest_values.length; i++){
|
||||||
|
|
||||||
TextView tv = new TextViewBuilder(getContext(), match_latest_values[i].name)
|
binding.matchArea.addView(
|
||||||
|
new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||||
.align_center()
|
.align_center()
|
||||||
.size(30)
|
.size(30)
|
||||||
.padding(0,0,20,5)
|
.padding(0,0,20,5)
|
||||||
.build();
|
.build()
|
||||||
tv.setPaintFlags(tv.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
);
|
||||||
binding.matchArea.addView(tv);
|
|
||||||
|
|
||||||
if(data[i] != null)
|
if(data[i] != null)
|
||||||
match_latest_values[i].add_history_view(binding.matchArea, data[i]);
|
match_latest_values[i].add_history_view(binding.matchArea, data[i]);
|
||||||
|
|||||||
@@ -157,35 +157,28 @@ public class ScoutingFragment extends Fragment {
|
|||||||
private void updateDashboard() {
|
private void updateDashboard() {
|
||||||
binding.textName.setText("Welcome, " + SettingsManager.getUsername() + "!");
|
binding.textName.setText("Welcome, " + SettingsManager.getUsername() + "!");
|
||||||
|
|
||||||
|
int curMatchNum = SettingsManager.getMatchNum();
|
||||||
|
int nextMatch;
|
||||||
|
int teamNum = SettingsManager.getTeamNum();
|
||||||
|
try {
|
||||||
|
nextMatch = event.getNextTeamMatch(teamNum, curMatchNum).matchIndex;
|
||||||
|
} catch (Exception e){
|
||||||
|
AlertManager.error("Sorry, in event ("+evcode+"), your team number ("+teamNum+") wasn't found!", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.textMatchAlliance.setText("Match: " + (curMatchNum+1) + ", " + SettingsManager.getAllyPos());
|
||||||
binding.textRescoutIndicator.setText("Things to rescout: " + DataManager.rescout_list.size());
|
binding.textRescoutIndicator.setText("Things to rescout: " + DataManager.rescout_list.size());
|
||||||
|
|
||||||
if(event.matches.size() == 0) {
|
binding.infoBox.addView(new TextViewBuilder(getContext(), "Our next match: Match " + nextMatch)
|
||||||
binding.textMatchAlliance.setText("No Matches!");
|
.body1()
|
||||||
} else {
|
.build());
|
||||||
int teamNum = SettingsManager.getTeamNum();
|
|
||||||
int curMatchNum = SettingsManager.getMatchNum();
|
|
||||||
|
|
||||||
binding.textMatchAlliance.setText("Match: " + (curMatchNum+1) + ", " + SettingsManager.getAllyPos());
|
int informedBy = event.getMostInformedBy(teamNum, curMatchNum);
|
||||||
|
|
||||||
int nextMatch;
|
|
||||||
try {
|
|
||||||
nextMatch = event.getNextTeamMatch(teamNum, curMatchNum).matchIndex;
|
|
||||||
} catch (Exception e){
|
|
||||||
AlertManager.error("Sorry, in event ("+evcode+"), your team number ("+teamNum+") wasn't found!", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
binding.infoBox.addView(new TextViewBuilder(getContext(), "Our next match: Match " + nextMatch)
|
binding.infoBox.addView(new TextViewBuilder(getContext(), "Most informed by: Match " + informedBy)
|
||||||
.body1()
|
.body1()
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
int informedBy = event.getMostInformedBy(teamNum, curMatchNum);
|
|
||||||
|
|
||||||
|
|
||||||
binding.infoBox.addView(new TextViewBuilder(getContext(), "Most informed by: Match " + informedBy)
|
|
||||||
.body1()
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,10 +18,14 @@ import com.ridgebotics.ridgescout.types.input.NumberType;
|
|||||||
import com.ridgebotics.ridgescout.types.input.SliderType;
|
import com.ridgebotics.ridgescout.types.input.SliderType;
|
||||||
import com.ridgebotics.ridgescout.types.input.TallyType;
|
import com.ridgebotics.ridgescout.types.input.TallyType;
|
||||||
import com.ridgebotics.ridgescout.types.input.TextType;
|
import com.ridgebotics.ridgescout.types.input.TextType;
|
||||||
|
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
// Class to help with fields editor fragment, containing the defaults for each field.
|
// Class to help with fields editor fragment, containing the defaults for each field.
|
||||||
@@ -30,7 +34,8 @@ public class FieldEditorHelper {
|
|||||||
paramNumber,
|
paramNumber,
|
||||||
paramString,
|
paramString,
|
||||||
paramStringArray,
|
paramStringArray,
|
||||||
paramNumberArray
|
paramNumberArray,
|
||||||
|
paramDropdown
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class parameterType {
|
public static class parameterType {
|
||||||
@@ -65,6 +70,17 @@ public class FieldEditorHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class paramDropdown extends parameterType{
|
||||||
|
public List<String> options;
|
||||||
|
public int val;
|
||||||
|
public paramDropdown(String name, List<String> options, int val){
|
||||||
|
this.name = name + " (Dropdown)";
|
||||||
|
this.options = options;
|
||||||
|
this.val = val;
|
||||||
|
this.id = parameterTypeEnum.paramDropdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public static class paramNumberArray extends parameterType{
|
// public static class paramNumberArray extends parameterType{
|
||||||
// public int[] val;
|
// public int[] val;
|
||||||
// public paramNumberArray(String name, int[] val){
|
// public paramNumberArray(String name, int[] val){
|
||||||
@@ -167,9 +183,16 @@ public class FieldEditorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static parameterType[] getFieldPosParam(FieldposType s){
|
private static parameterType[] getFieldPosParam(FieldposType s){
|
||||||
|
FieldposType.FieldImage[] f_images = FieldposType.FieldImage.values();
|
||||||
|
List<String> images = new ArrayList<>();
|
||||||
|
for (FieldposType.FieldImage fimage: f_images) {
|
||||||
|
images.add(fimage.toString());
|
||||||
|
}
|
||||||
|
|
||||||
return new parameterType[]{
|
return new parameterType[]{
|
||||||
new paramString("Name", s.name),
|
new paramString("Name", s.name),
|
||||||
new paramString("Description", s.description),
|
new paramString("Description", s.description),
|
||||||
|
new paramDropdown("Field Image", images, 0),
|
||||||
new paramNumber("Default X", ((int[]) s.default_value)[0]),
|
new paramNumber("Default X", ((int[]) s.default_value)[0]),
|
||||||
new paramNumber("Default Y", ((int[]) s.default_value)[1])
|
new paramNumber("Default Y", ((int[]) s.default_value)[1])
|
||||||
};
|
};
|
||||||
@@ -219,9 +242,10 @@ public class FieldEditorHelper {
|
|||||||
public static void setFieldPosParam(FieldposType s, parameterType[] types){
|
public static void setFieldPosParam(FieldposType s, parameterType[] types){
|
||||||
s.name = ((paramString) types[0]).val;
|
s.name = ((paramString) types[0]).val;
|
||||||
s.description = ((paramString) types[1]).val;
|
s.description = ((paramString) types[1]).val;
|
||||||
|
s.fieldImage = FieldposType.FieldImage.from_index(((paramDropdown) types[2]).val);
|
||||||
s.default_value = new int[]{
|
s.default_value = new int[]{
|
||||||
((paramNumber) types[2]).val,
|
((paramNumber) types[3]).val,
|
||||||
((paramNumber) types[3]).val
|
((paramNumber) types[4]).val
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +331,24 @@ public class FieldEditorHelper {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static View createDropdown(Context c, String name, List<String> options, int value){
|
||||||
|
CustomSpinnerView spinner = new CustomSpinnerView(c);
|
||||||
|
spinner.setTitle(name);
|
||||||
|
spinner.setOptions(options, value);
|
||||||
|
spinner.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
// EditText text = new EditText(c);
|
||||||
|
// text.setText(String.join("\n", value));
|
||||||
|
// text.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
// ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
// ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
// ));
|
||||||
|
return spinner;
|
||||||
|
}
|
||||||
|
|
||||||
private static View createEdit(Context c, parameterType t){
|
private static View createEdit(Context c, parameterType t){
|
||||||
switch (t.id){
|
switch (t.id){
|
||||||
case paramNumber:
|
case paramNumber:
|
||||||
@@ -315,6 +357,8 @@ public class FieldEditorHelper {
|
|||||||
return createStringEdit(c, ((paramString) t).val);
|
return createStringEdit(c, ((paramString) t).val);
|
||||||
case paramStringArray:
|
case paramStringArray:
|
||||||
return createStringArrayEdit(c, ((paramStringArray) t).val);
|
return createStringArrayEdit(c, ((paramStringArray) t).val);
|
||||||
|
case paramDropdown:
|
||||||
|
return createDropdown(c, t.name, ((paramDropdown) t).options, ((paramDropdown) t).val);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -322,22 +366,27 @@ public class FieldEditorHelper {
|
|||||||
|
|
||||||
private static boolean readEdit(View v, parameterType t){
|
private static boolean readEdit(View v, parameterType t){
|
||||||
try{
|
try{
|
||||||
String val;
|
// String val;
|
||||||
switch (t.id) {
|
switch (t.id) {
|
||||||
case paramNumber:
|
case paramNumber:
|
||||||
val = ((EditText) v).getText().toString();
|
String val1 = ((EditText) v).getText().toString();
|
||||||
if(val.isEmpty() || val.isBlank()) return false;
|
if(val1.isEmpty() || val1.isBlank()) return false;
|
||||||
((paramNumber) t).val = Integer.parseInt(val);
|
((paramNumber) t).val = Integer.parseInt(val1);
|
||||||
break;
|
break;
|
||||||
case paramString:
|
case paramString:
|
||||||
val = ((EditText) v).getText().toString();
|
String val2 = ((EditText) v).getText().toString();
|
||||||
//if(val.isEmpty() || val.isBlank()) return false;
|
//if(val.isEmpty() || val.isBlank()) return false;
|
||||||
((paramString) t).val = val;
|
((paramString) t).val = val2;
|
||||||
break;
|
break;
|
||||||
case paramStringArray:
|
case paramStringArray:
|
||||||
val = ((EditText) v).getText().toString();
|
String val3 = ((EditText) v).getText().toString();
|
||||||
if(val.isEmpty() || val.isBlank()) return false;
|
if(val3.isEmpty() || val3.isBlank()) return false;
|
||||||
((paramStringArray) t).val = val.split("\n");
|
((paramStringArray) t).val = val3.split("\n");
|
||||||
|
break;
|
||||||
|
case paramDropdown:
|
||||||
|
int val4 = ((CustomSpinnerView) v).getIndex();
|
||||||
|
// if(val.isEmpty() || val.isBlank()) return false;
|
||||||
|
((paramDropdown) t).val = val4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -151,12 +151,7 @@ public class SettingsFragment extends Fragment {
|
|||||||
|
|
||||||
|
|
||||||
manager.addItem(new CheckboxSettingsItem(EnableQuickAllianceChangeKey, "Enable quick alliance swap", null));
|
manager.addItem(new CheckboxSettingsItem(EnableQuickAllianceChangeKey, "Enable quick alliance swap", null));
|
||||||
manager.addItem(new DropdownSettingsItem(FieldImageKey, "Field Image", new String[]{
|
manager.addItem(new CheckboxSettingsItem(FieldImageKey, "Field Image", null));
|
||||||
"2026",
|
|
||||||
"2026 (Flipped)",
|
|
||||||
"2025",
|
|
||||||
"2025 (Flipped)"
|
|
||||||
}));
|
|
||||||
|
|
||||||
manager.addItem(new DropdownSettingsItem(AllyPosKey, "Alliance Pos", alliance_pos_list));
|
manager.addItem(new DropdownSettingsItem(AllyPosKey, "Alliance Pos", alliance_pos_list));
|
||||||
|
|
||||||
|
|||||||
@@ -174,24 +174,23 @@ public class HttpSync extends Thread {
|
|||||||
|
|
||||||
TransferFile localFile = findInFileArray(localFiles, remoteFile.filename);
|
TransferFile localFile = findInFileArray(localFiles, remoteFile.filename);
|
||||||
|
|
||||||
boolean shouldDownload;
|
boolean shouldUpload;
|
||||||
|
|
||||||
// If there is no file on the sever, upload.
|
// If there is no file on the sever, upload.
|
||||||
if(localFile == null) {
|
if(localFile == null) {
|
||||||
shouldDownload = true;
|
shouldUpload = true;
|
||||||
} else {
|
} else {
|
||||||
// If the remote file is the same as the local one, do nothing.
|
// If the remote file is the same as the local one, do nothing.
|
||||||
|
boolean checksumsEqual = !Objects.equals(localFile.checksum, remoteFile.checksum);
|
||||||
boolean checksumsNotEqual = !Objects.equals(localFile.checksum, remoteFile.checksum);
|
|
||||||
// If the local file is updated after the remote file
|
// If the local file is updated after the remote file
|
||||||
boolean after = after(remoteFile.updated, localFile.updated);
|
boolean after = after(remoteFile.updated, localFile.updated);
|
||||||
// If the local file and remote file's upload dates are exactly the same
|
// If the local file and remote file's upload dates are exactly the same
|
||||||
boolean datesNotEqual = !localFile.updated.equals(remoteFile.updated);
|
boolean datesEqual = !localFile.updated.equals(remoteFile.updated);
|
||||||
|
|
||||||
shouldDownload = checksumsNotEqual && after;
|
shouldUpload = (!checksumsEqual && (after) && !datesEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(shouldDownload) {
|
if(shouldUpload) {
|
||||||
downloadFile(remoteFile, serverIP);
|
downloadFile(remoteFile, serverIP);
|
||||||
// await();
|
// await();
|
||||||
Log.d(getClass().toString(), "RemoteFile: " + remoteFile.filename + ", " + remoteFile.checksum + ", " + remoteFile.updated + ": Downloaded");
|
Log.d(getClass().toString(), "RemoteFile: " + remoteFile.filename + ", " + remoteFile.checksum + ", " + remoteFile.updated + ": Downloaded");
|
||||||
|
|||||||
@@ -165,12 +165,12 @@ public class TBASelectorFragment extends Fragment {
|
|||||||
try {
|
try {
|
||||||
Date startDate = format.parse(j.getString("start_date"));
|
Date startDate = format.parse(j.getString("start_date"));
|
||||||
Date endDate = format.parse(j.getString("end_date"));
|
Date endDate = format.parse(j.getString("end_date"));
|
||||||
if(currentTime.after(startDate) && currentTime.before(endDate)) {
|
if(currentTime.after(endDate)){
|
||||||
row.setColor(tba_current);
|
|
||||||
} else if(currentTime.after(endDate)){
|
|
||||||
row.setColor(tba_previous);
|
row.setColor(tba_previous);
|
||||||
}else if(currentTime.before(startDate)){
|
}else if(currentTime.before(startDate)){
|
||||||
row.setColor(tba_next);
|
row.setColor(tba_next);
|
||||||
|
}else if(currentTime.after(startDate) && currentTime.before(endDate)){
|
||||||
|
row.setColor(tba_current);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
AlertManager.error("Failed finding start and end dates!", e);
|
AlertManager.error("Failed finding start and end dates!", e);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
import com.ridgebotics.ridgescout.types.input.FieldposType;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
|
||||||
// Custom view to display a field position.
|
// Custom view to display a field position.
|
||||||
@@ -24,6 +25,8 @@ public class FieldPosView extends FrameLayout {
|
|||||||
private ImageView imageView;
|
private ImageView imageView;
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
private boolean flip = false;
|
||||||
|
|
||||||
public interface onTapListener {
|
public interface onTapListener {
|
||||||
void onUpdate(int[] pos);
|
void onUpdate(int[] pos);
|
||||||
};
|
};
|
||||||
@@ -65,30 +68,21 @@ public class FieldPosView extends FrameLayout {
|
|||||||
// Set touch listener
|
// Set touch listener
|
||||||
setOnTouchListener((v, event) -> {
|
setOnTouchListener((v, event) -> {
|
||||||
if (enabled && event.getAction() == MotionEvent.ACTION_DOWN) {
|
if (enabled && event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
x = (int) ((event.getX()/getWidth())*255);
|
// If the field image is rotated, rotate the input and output
|
||||||
y = (int) ((event.getY()/getHeight())*255);
|
if(!flip) {
|
||||||
|
x = (int) (event.getX() / getWidth()) * 255;
|
||||||
|
y = (int) (event.getY() / getHeight()) * 255;
|
||||||
|
} else {
|
||||||
|
x = (int) (1 - (event.getX() / getWidth())) * 255;
|
||||||
|
y = (int) (1 - (event.getY() / getHeight())) * 255;
|
||||||
|
}
|
||||||
|
System.out.println("X: " + x + ", Y: " + y);
|
||||||
tl.onUpdate(getPos());
|
tl.onUpdate(getPos());
|
||||||
invalidate();
|
invalidate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
switch(SettingsManager.getFieldImageIndex()){
|
|
||||||
case "2025":
|
|
||||||
setImageResource(R.drawable.field_2025);
|
|
||||||
break;
|
|
||||||
case "2025 (Flipped)":
|
|
||||||
setImageResource(R.drawable.field_2025_flipped);
|
|
||||||
break;
|
|
||||||
case "2026":
|
|
||||||
setImageResource(R.drawable.field_2026);
|
|
||||||
break;
|
|
||||||
case "2026 (Flipped)":
|
|
||||||
setImageResource(R.drawable.field_2026_flipped);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPos(int[] pos){
|
public void setPos(int[] pos){
|
||||||
@@ -102,10 +96,28 @@ public class FieldPosView extends FrameLayout {
|
|||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
if (x >= 0 && y >= 0) {
|
if (x >= 0 && y >= 0) {
|
||||||
canvas.drawCircle(
|
|
||||||
((float) x /255)*getWidth(),
|
float cx;
|
||||||
((float) y /255)*getHeight(),
|
float cy;
|
||||||
POINT_RADIUS, paint);
|
// If the field image is rotated, rotate the input and output
|
||||||
|
if(!flip) {
|
||||||
|
cx = ((float) x / 255)*getWidth();
|
||||||
|
cy = ((float) y / 255)*getHeight();
|
||||||
|
} else {
|
||||||
|
cx = (1 - (float) x / 255)*getWidth();
|
||||||
|
cy = (1 - (float) y /255)*getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawCircle(cx, cy, POINT_RADIUS, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldImage(FieldposType.FieldImage image) {
|
||||||
|
if(image.flippable && SettingsManager.getFieldImageFlipped()) {
|
||||||
|
setImageResource(image.resId_flipped);
|
||||||
|
flip = true;
|
||||||
|
} else {
|
||||||
|
setImageResource(image.resId_normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
import com.ridgebotics.ridgescout.types.input.FieldposType;
|
||||||
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -48,9 +50,6 @@ public class MultiFieldPosView extends FrameLayout {
|
|||||||
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||||
imageView.setAdjustViewBounds(true);
|
imageView.setAdjustViewBounds(true);
|
||||||
addView(imageView);
|
addView(imageView);
|
||||||
|
|
||||||
setImageResource(R.drawable.field_2025);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPos(int[] pos){
|
public void addPos(int[] pos){
|
||||||
@@ -62,6 +61,14 @@ public class MultiFieldPosView extends FrameLayout {
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFieldImage(FieldposType.FieldImage image) {
|
||||||
|
if(image.flippable && SettingsManager.getFieldImageFlipped()) {
|
||||||
|
setImageResource(image.resId_flipped);
|
||||||
|
} else {
|
||||||
|
setImageResource(image.resId_normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ public class Colors {
|
|||||||
public static final int fileselector_unselected_color = 0x50006600;
|
public static final int fileselector_unselected_color = 0x50006600;
|
||||||
|
|
||||||
// TBA
|
// TBA
|
||||||
public static final int tba_previous = Color.argb(30, 64,64,64);
|
public static final int tba_previous = 0x30FF0000;
|
||||||
public static final int tba_current = 0x7f00ff00;
|
public static final int tba_current = 0x50ff0000;
|
||||||
public static final int tba_next = Color.argb(30, 192,192,192);
|
public static final int tba_next = 0x30FFFF00;
|
||||||
public static final int tba_red = 0x50ff0000;
|
public static final int tba_red = 0x50ff0000;
|
||||||
public static final int tba_blue = 0x500000ff;
|
public static final int tba_blue = 0x500000ff;
|
||||||
public static final int tba_toggle_background = 0x30000000;
|
public static final int tba_toggle_background = 0x30000000;
|
||||||
|
|||||||
@@ -263,11 +263,6 @@ public final class FileEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the date modified to a long, long time ago
|
|
||||||
public static boolean toTheArchaicPeriod(String name) {
|
|
||||||
return new File(baseDir + name).setLastModified(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean createFile(String filepath){
|
public static boolean createFile(String filepath){
|
||||||
if(fileExist(filepath)){
|
if(fileExist(filepath)){
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class SettingsManager {
|
|||||||
|
|
||||||
public static final String SelEVCodeKey = "selected_event_code";
|
public static final String SelEVCodeKey = "selected_event_code";
|
||||||
public static final String YearNumKey = "year_num";
|
public static final String YearNumKey = "year_num";
|
||||||
public static final String FieldImageKey = "field_image";
|
public static final String FieldImageKey = "field_image_flipped";
|
||||||
|
|
||||||
public static final String MatchNumKey = "match_num";
|
public static final String MatchNumKey = "match_num";
|
||||||
public static final String AllyPosKey = "alliance_pos";
|
public static final String AllyPosKey = "alliance_pos";
|
||||||
@@ -46,8 +46,8 @@ public class SettingsManager {
|
|||||||
hm.put(UnameKey, "Username");
|
hm.put(UnameKey, "Username");
|
||||||
hm.put(SelEVCodeKey, "unset");
|
hm.put(SelEVCodeKey, "unset");
|
||||||
hm.put(WifiModeKey, false);
|
hm.put(WifiModeKey, false);
|
||||||
hm.put(YearNumKey, 2026);
|
hm.put(YearNumKey, 2025);
|
||||||
hm.put(FieldImageKey, "2026");
|
hm.put(FieldImageKey, false);
|
||||||
hm.put(MatchNumKey, 0);
|
hm.put(MatchNumKey, 0);
|
||||||
hm.put(AllyPosKey, "red-1");
|
hm.put(AllyPosKey, "red-1");
|
||||||
hm.put(DataModeKey, 0);
|
hm.put(DataModeKey, 0);
|
||||||
@@ -77,7 +77,7 @@ public class SettingsManager {
|
|||||||
getEditor().putBoolean(WifiModeKey, (boolean) defaults.get( WifiModeKey )).apply();
|
getEditor().putBoolean(WifiModeKey, (boolean) defaults.get( WifiModeKey )).apply();
|
||||||
|
|
||||||
getEditor() .putInt(YearNumKey, (int) defaults.get( YearNumKey )).apply();
|
getEditor() .putInt(YearNumKey, (int) defaults.get( YearNumKey )).apply();
|
||||||
getEditor() .putString(FieldImageKey, (String) defaults.get( FieldImageKey )).apply();
|
getEditor() .putBoolean(FieldImageKey, (boolean) defaults.get( FieldImageKey )).apply();
|
||||||
getEditor() .putInt(MatchNumKey, (int) defaults.get( MatchNumKey )).apply();
|
getEditor() .putInt(MatchNumKey, (int) defaults.get( MatchNumKey )).apply();
|
||||||
getEditor() .putString(AllyPosKey, (String) defaults.get( AllyPosKey )).apply();
|
getEditor() .putString(AllyPosKey, (String) defaults.get( AllyPosKey )).apply();
|
||||||
getEditor() .putInt(DataModeKey, (int) defaults.get( DataModeKey )).apply();
|
getEditor() .putInt(DataModeKey, (int) defaults.get( DataModeKey )).apply();
|
||||||
@@ -108,8 +108,8 @@ public class SettingsManager {
|
|||||||
public static int getYearNum(){return prefs.getInt( YearNumKey, (int) defaults.get(YearNumKey));}
|
public static int getYearNum(){return prefs.getInt( YearNumKey, (int) defaults.get(YearNumKey));}
|
||||||
public static void setYearNum(int num){ getEditor().putInt( YearNumKey,num).apply();}
|
public static void setYearNum(int num){ getEditor().putInt( YearNumKey,num).apply();}
|
||||||
|
|
||||||
public static String getFieldImageIndex(){return prefs.getString( FieldImageKey, (String) defaults.get(FieldImageKey));}
|
public static boolean getFieldImageFlipped(){return prefs.getBoolean(FieldImageKey, (boolean) defaults.get(FieldImageKey));}
|
||||||
public static void setFieldImageIndex(String str){ getEditor().putString( FieldImageKey,str).apply();}
|
public static void setFieldImageFlipped(boolean bool){ getEditor().putBoolean(FieldImageKey, bool).apply();}
|
||||||
|
|
||||||
public static int getMatchNum(){return prefs.getInt( MatchNumKey, (int) defaults.get(MatchNumKey));}
|
public static int getMatchNum(){return prefs.getInt( MatchNumKey, (int) defaults.get(MatchNumKey));}
|
||||||
public static void setMatchNum(int num){ getEditor().putInt( MatchNumKey,num).apply();}
|
public static void setMatchNum(int num){ getEditor().putInt( MatchNumKey,num).apply();}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 636 KiB |
|
Before Width: | Height: | Size: 954 KiB |
@@ -60,7 +60,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Pit Data"
|
android:text="Pit Data"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textSize="35sp"
|
android:textSize="24sp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/team_description2"
|
app:layout_constraintTop_toBottomOf="@+id/team_description2"
|
||||||
tools:layout_editor_absoluteX="0dp" />
|
tools:layout_editor_absoluteX="0dp" />
|
||||||
|
|
||||||
@@ -73,11 +73,6 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/divider3"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="12dp"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -86,7 +81,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Match Data"
|
android:text="Match Data"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textSize="35sp"
|
android:textSize="24sp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/team_description2"
|
app:layout_constraintTop_toBottomOf="@+id/team_description2"
|
||||||
tools:layout_editor_absoluteX="0dp" />
|
tools:layout_editor_absoluteX="0dp" />
|
||||||
|
|
||||||
@@ -144,13 +139,9 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/divider2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.13.2"
|
agp = "8.13.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.1.5"
|
junitVersion = "1.1.5"
|
||||||
espressoCore = "3.5.1"
|
espressoCore = "3.5.1"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 493 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 162 KiB |
@@ -17,6 +17,7 @@ dependencyResolutionManagement {
|
|||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven ( url = "https://jitpack.io" )
|
maven ( url = "https://jitpack.io" )
|
||||||
|
jcenter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||