Compare commits
24 Commits
recyclerview
..
v3.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 76a1b1ff70 | |||
| 82465f213f | |||
| 3c7a879f51 | |||
| 3157de62ff | |||
| 5ddc032be9 | |||
| e6073ded49 | |||
| 7503cefa09 | |||
| 3b4737e6bc | |||
| 76d28e46cd | |||
| 73308f2acc | |||
| c18a93cb1a | |||
| 3ca601f080 | |||
| 4554db9dc7 | |||
| b5b1100c2c | |||
| 311dfcbd5d | |||
| fa47eb1aff | |||
| 93b58310bf | |||
| 859d3bc773 | |||
| 9136df04df | |||
| f281ff2f0a | |||
| 154e76fbf7 | |||
| ffaec948b4 | |||
| 2d3db09aae | |||
| ef761003c8 |
@@ -11,10 +11,10 @@
|
||||
|
||||
#### 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.
|
||||
- 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 loosing any data!
|
||||
- Similar to ScoutingPASS, many different types of fields can be used to collect data.
|
||||
- The app is designed to handle updates to the fields on the fly, without losing 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.
|
||||
- Dynamic displays based off of the diffrent fields.
|
||||
- Dynamic displays based on the different fields.
|
||||
- Data transfer including 2D codes, Bluetooth, and File Bundle.
|
||||
- Exporting using CSV.
|
||||
- Deployment on F-Droid
|
||||
@@ -22,10 +22,9 @@
|
||||
|
||||
#### Things that are yet to be implemented:
|
||||
- A page that lets users cross-compare scouting data between teams. (Compare)
|
||||
- A page that lets scouters more easily make reports to the drive team before a match starts (Report)
|
||||
|
||||
#### Things that may or may not be implemented:
|
||||
- Statbotics intgration
|
||||
- Statbotics integration
|
||||
- Scout error estimation using OPR-like calculation
|
||||
- - Would most likely require Statbotics
|
||||
https://www.thebluealliance.com/avatars
|
||||
@@ -33,4 +32,3 @@ https://www.thebluealliance.com/avatars
|
||||
|Match scouting interface|Field editor|Teams data viewer|
|
||||
|-|-|-|
|
||||
||||
|
||||
z
|
||||
@@ -16,7 +16,7 @@ android {
|
||||
dependenciesInfo {
|
||||
// Disables dependency metadata when building APKs.
|
||||
includeInApk = false
|
||||
// Disables dependency metadata when building Android App Bundles.
|
||||
// Disables dependency metadata when building Android App Bundles.5
|
||||
includeInBundle = false
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ android {
|
||||
applicationId = "com.ridgebotics.ridgescout"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 11 // **IMPORTANT** Increment this before releasing on github
|
||||
versionName = "1.4"// **IMPORTANT** Change this before releasing on github (<Year num since 2024>.<Update Version>)
|
||||
versionCode = 15 // **IMPORTANT** Increment this before releasing on github
|
||||
versionName = "3.1"// **IMPORTANT** Change this before releasing on github (<Year num since 2024>.<Update Version>)
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -44,8 +44,8 @@ android {
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
aaptOptions {
|
||||
noCompress("tflite");
|
||||
androidResources {
|
||||
noCompress += listOf("tflite")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,13 +57,11 @@ dependencies {
|
||||
implementation(libs.constraintlayout)
|
||||
implementation(libs.lifecycle.livedata.ktx)
|
||||
implementation(libs.lifecycle.viewmodel.ktx)
|
||||
implementation(libs.navigation.fragment.v289)
|
||||
implementation("androidx.navigation:navigation-fragment:2.8.9")
|
||||
implementation(libs.navigation.ui)
|
||||
implementation(libs.preference)
|
||||
// implementation(libs.asynclayoutinflator)
|
||||
|
||||
// implementation(libs.support.annotations)
|
||||
testImplementation(libs.junit)
|
||||
|
||||
androidTestImplementation(libs.ext.junit)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
|
||||
|
||||
@@ -47,11 +47,13 @@ public class MainActivity extends AppCompatActivity {
|
||||
// Load default match fields
|
||||
if(!FileEditor.fileExist(Fields.matchFieldsFilename)){
|
||||
Fields.save(Fields.matchFieldsFilename, Fields.default_match_fields);
|
||||
FileEditor.toTheArchaicPeriod(Fields.matchFieldsFilename);
|
||||
}
|
||||
|
||||
// Load default pit fields
|
||||
if(!FileEditor.fileExist(Fields.pitsFieldsFilename)){
|
||||
Fields.save(Fields.pitsFieldsFilename, Fields.default_pit_fields);
|
||||
FileEditor.toTheArchaicPeriod(Fields.pitsFieldsFilename);
|
||||
}
|
||||
|
||||
// get time zone for FTP file transfer
|
||||
|
||||
@@ -30,36 +30,7 @@ public class Fields {
|
||||
|
||||
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 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 auto?", 0),
|
||||
new TallyType(uuid(),"Teleop L3 Coral", "How many coral did this robot score in L3 during auto?", 0),
|
||||
new TallyType(uuid(),"Teleop L2 Coral", "How many coral did this robot score in L2 during auto?", 0),
|
||||
new TallyType(uuid(),"Teleop L1 Coral", "How many coral did this robot score in L1 during auto?", 0),
|
||||
new TallyType(uuid(),"Teleop Processor Algae", "How many algae did this robot score in the Barge during auto?", 0),
|
||||
new TallyType(uuid(),"Teleop Barge Algae", "How many algae did this robot score in the Barge during auto?", 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", "")
|
||||
new FieldposType(uuid(),"Auto start pos", "Where does the robot start its auto?", new int[]{0,0})
|
||||
}
|
||||
};
|
||||
|
||||
@@ -69,14 +40,6 @@ 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 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 TextType(uuid(),"Auto Capability", "What autos does this team have?", ""),
|
||||
|
||||
@@ -60,61 +60,57 @@ public class ScoutingDataWriter {
|
||||
public ScoutingArray data;
|
||||
}
|
||||
|
||||
public static ParsedScoutingDataResult load(String filename, FieldType[][] values , TransferType[][] transferValues){
|
||||
public static ParsedScoutingDataResult load(String filename, FieldType[][] values , TransferType[][] transferValues) throws BuiltByteParser.byteParsingExeption{
|
||||
byte[] bytes = FileEditor.readFile(filename);
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
|
||||
try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
RawDataType[] rawDataTypes = new RawDataType[objects.size()-2];
|
||||
// try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||
RawDataType[] rawDataTypes = new RawDataType[objects.size()-2];
|
||||
|
||||
int version = ((int)objects.get(0).get());
|
||||
int version = ((int)objects.get(0).get());
|
||||
|
||||
if(values.length <= version) {
|
||||
if(values.length <= version) {
|
||||
// AlertManager.addSimpleError("Error loading " + filename);
|
||||
AlertManager.error(new BuiltByteParser.byteParsingExeption("Field version (" +version + ") is too recent as compared to latest version (" + (values.length-1) + ")!"));
|
||||
return null;
|
||||
}
|
||||
throw new BuiltByteParser.byteParsingExeption("Field version (" +version + ") is too recent as compared to latest version (" + (values.length-1) + ")!");
|
||||
}
|
||||
|
||||
// System.out.println(version);
|
||||
String username = (String) objects.get(1).get();
|
||||
String username = (String) objects.get(1).get();
|
||||
|
||||
for(int i = 0; i < values[version].length; i++){
|
||||
switch (objects.get(i+2).getType()){
|
||||
case 1: // Int
|
||||
rawDataTypes[i] = IntType.newNull(values[version][i].UUID);
|
||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded INT: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
||||
break;
|
||||
case 2: // String
|
||||
rawDataTypes[i] = StringType.newNull(values[version][i].UUID);
|
||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded STR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
||||
break;
|
||||
case 3: // Int array
|
||||
rawDataTypes[i] = IntArrType.newNull(values[version][i].UUID);
|
||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded intARR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ Arrays.toString((int[]) rawDataTypes[i].get()) +")");
|
||||
break;
|
||||
}
|
||||
for(int i = 0; i < values[version].length; i++){
|
||||
switch (objects.get(i+2).getType()){
|
||||
case 1: // Int
|
||||
rawDataTypes[i] = IntType.newNull(values[version][i].UUID);
|
||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded INT: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
||||
break;
|
||||
case 2: // String
|
||||
rawDataTypes[i] = StringType.newNull(values[version][i].UUID);
|
||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded STR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
||||
break;
|
||||
case 3: // Int array
|
||||
rawDataTypes[i] = IntArrType.newNull(values[version][i].UUID);
|
||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded intARR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ Arrays.toString((int[]) rawDataTypes[i].get()) +")");
|
||||
break;
|
||||
}
|
||||
|
||||
ScoutingArray msa = new ScoutingArray(version, rawDataTypes, values, transferValues);
|
||||
msa.update();
|
||||
|
||||
ParsedScoutingDataResult psda = new ParsedScoutingDataResult();
|
||||
|
||||
psda.filename = filename;
|
||||
psda.username = username;
|
||||
psda.version = version;
|
||||
psda.data = msa;
|
||||
|
||||
return psda;
|
||||
|
||||
} catch (BuiltByteParser.byteParsingExeption e){
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
ScoutingArray msa = new ScoutingArray(version, rawDataTypes, values, transferValues);
|
||||
msa.update();
|
||||
|
||||
ParsedScoutingDataResult psda = new ParsedScoutingDataResult();
|
||||
|
||||
psda.filename = filename;
|
||||
psda.username = username;
|
||||
psda.version = version;
|
||||
psda.data = msa;
|
||||
|
||||
return psda;
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
// A function that takes in a list of names seperated by commas, and adds a name if it is not included
|
||||
|
||||
@@ -1,4 +1,179 @@
|
||||
package com.ridgebotics.ridgescout.types;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ColabArray {
|
||||
private enum Action {
|
||||
ADD,
|
||||
REMOVE
|
||||
}
|
||||
|
||||
private List<Diff> changelog = new ArrayList<>();
|
||||
|
||||
private void addChange(Diff change) {
|
||||
this.changelog.add(change);
|
||||
}
|
||||
|
||||
private List<Diff> getChangelog() {
|
||||
return changelog;
|
||||
}
|
||||
|
||||
public void add(String item) {
|
||||
Diff diff = new Diff();
|
||||
diff.action = Action.ADD;
|
||||
diff.content = item;
|
||||
diff.time = new Date();
|
||||
addChange(diff);
|
||||
}
|
||||
|
||||
public void remove(String item) {
|
||||
Diff diff = new Diff();
|
||||
diff.action = Action.REMOVE;
|
||||
diff.content = item;
|
||||
diff.time = new Date();
|
||||
addChange(diff);
|
||||
}
|
||||
|
||||
public void remove(int index) {
|
||||
remove(get().get(index));
|
||||
}
|
||||
|
||||
private static class Diff {
|
||||
public Action action;
|
||||
public String content;
|
||||
public Date time;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj.getClass() != this.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Diff other = (Diff) obj;
|
||||
|
||||
return other.action == this.action &&
|
||||
other.time.getTime() == this.time.getTime() &&
|
||||
other.content.equals(this.content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public byte[] encode() throws ByteBuilder.buildingException{
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
|
||||
for(Diff change : this.changelog){
|
||||
bb.addInt(change.action.ordinal());
|
||||
bb.addString(change.content);
|
||||
bb.addLong(change.time.getTime());
|
||||
}
|
||||
|
||||
|
||||
return bb.build();
|
||||
}
|
||||
|
||||
public static ColabArray decode(byte[] bytes) throws BuiltByteParser.byteParsingExeption {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
List<BuiltByteParser.parsedObject> results = bbp.parse();
|
||||
|
||||
if(results.size() % 3 != 0){
|
||||
throw new BuiltByteParser.byteParsingExeption("Wrong amount of elements in ColabArray!");
|
||||
}
|
||||
|
||||
ColabArray arr = new ColabArray();
|
||||
|
||||
for(int i = 0; i < results.size(); i += 3) {
|
||||
Diff diff = new Diff();
|
||||
diff.action = Action.values()[(int) results.get(i).get()];
|
||||
diff.content = (String) results.get(i+1).get();
|
||||
diff.time = new Date((long) results.get(i+2).get());
|
||||
arr.addChange(diff);
|
||||
}
|
||||
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public void append(ColabArray other) {
|
||||
|
||||
List<Diff> otherlog = other.getChangelog();
|
||||
|
||||
otherlog.removeIf(diff ->
|
||||
this.changelog.contains(diff)
|
||||
);
|
||||
|
||||
this.changelog.addAll(otherlog);
|
||||
this.changelog = Arrays.asList(sort(this.changelog));
|
||||
}
|
||||
|
||||
public void append(File other) {
|
||||
byte[] bytes = FileEditor.readFile(other);
|
||||
if(bytes == null) return;
|
||||
try {
|
||||
append(decode(bytes));
|
||||
} catch (BuiltByteParser.byteParsingExeption e) {
|
||||
AlertManager.error("Failed to append ColabArray!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Diff[] sort(List<Diff> changelog) {
|
||||
Diff[] sorted = changelog.toArray(new Diff[0]);
|
||||
|
||||
try {
|
||||
Arrays.sort(sorted, (o1, o2) -> (int) (o1.time.getTime() - o2.time.getTime()));
|
||||
} catch (Exception e){
|
||||
AlertManager.error(e);
|
||||
}
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
public List<String> get() {
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
for(Diff change : changelog) {
|
||||
switch (change.action) {
|
||||
case ADD:
|
||||
result.add(change.content);
|
||||
break;
|
||||
case REMOVE:
|
||||
result.remove(change.content);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean contains(String item) {
|
||||
// Diff[] sorted = sort();
|
||||
|
||||
for(int i = changelog.size()-1; i >= 0; i--) {
|
||||
Diff change = changelog.get(i);
|
||||
if(!change.content.equals(item)) continue;
|
||||
return change.action == Action.ADD;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return get().size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ public class ScoutingArray {
|
||||
continue;
|
||||
case CREATE:
|
||||
new_values[i] = create_transfer((CreateTransferType) tv);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.array = new_values;
|
||||
@@ -72,12 +71,6 @@ public class ScoutingArray {
|
||||
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){
|
||||
FieldType it = get_input_type_by_UUID(version+1, tv.UUID);
|
||||
switch (it.getValueType()){
|
||||
|
||||
@@ -32,12 +32,6 @@ public class ScoutingFile {
|
||||
ByteBuilder bb = new ByteBuilder()
|
||||
.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)));
|
||||
|
||||
return bb.build();
|
||||
|
||||
@@ -16,11 +16,14 @@ import java.util.stream.IntStream;
|
||||
// Class to contain data for an entire event.
|
||||
// Easily encoded and decoded to binary format.
|
||||
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 ArrayList<frcMatch> matches;
|
||||
public ArrayList<frcTeam> teams;
|
||||
|
||||
// Turns frcEvent into raw data
|
||||
public byte[] encode() {
|
||||
try {
|
||||
ByteBuilder bb = new ByteBuilder()
|
||||
@@ -46,6 +49,7 @@ public class frcEvent {
|
||||
}
|
||||
}
|
||||
|
||||
//Decodes the frcEvent
|
||||
public static frcEvent decode(byte[] bytes) {
|
||||
try {
|
||||
ArrayList<BuiltByteParser.parsedObject> objects =
|
||||
@@ -74,6 +78,7 @@ public class frcEvent {
|
||||
}
|
||||
}
|
||||
|
||||
//Generates text
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return (
|
||||
|
||||
@@ -207,6 +207,7 @@ public class CheckboxType extends FieldType {
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
//TODO
|
||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ 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.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -102,19 +103,17 @@ public class DropdownType extends FieldType {
|
||||
|
||||
|
||||
|
||||
|
||||
// Dropdown view
|
||||
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.setPadding(20,20,20,20);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(text_options[(int) data.get()]);
|
||||
tv.setTextSize(18);
|
||||
parent.addView(tv);
|
||||
|
||||
parent.addView(
|
||||
new TextViewBuilder(parent.getContext(), text_options[(int) data.get()])
|
||||
.layout_match_wrap()
|
||||
.padding(20)
|
||||
.size(18)
|
||||
.align_left()
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +122,7 @@ public class DropdownType extends FieldType {
|
||||
|
||||
|
||||
|
||||
|
||||
// Generates N amount of colors, all opposite colors
|
||||
private static int[] generateEquidistantColors(int N) {
|
||||
int[] colors = new int[N];
|
||||
float[] hsv = new float[3]; // Hue, Saturation, Value
|
||||
@@ -139,6 +138,7 @@ public class DropdownType extends FieldType {
|
||||
return colors;
|
||||
}
|
||||
|
||||
// Turns the dropdown into a pie chart in the compiled view
|
||||
public void add_compiled_view(LinearLayout parent, RawDataType[] data){
|
||||
PieChart chart = new PieChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
@@ -172,7 +172,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){
|
||||
LineChart chart = new LineChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
@@ -239,6 +239,7 @@ public class DropdownType extends FieldType {
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
//TODO
|
||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||
|
||||
}
|
||||
|
||||
@@ -221,6 +221,7 @@ public class FieldposType extends FieldType {
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
//TODO
|
||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.ridgebotics.ridgescout.types.data.RawDataType;
|
||||
import com.ridgebotics.ridgescout.types.data.IntType;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -118,16 +119,11 @@ public class NumberType extends FieldType {
|
||||
|
||||
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);
|
||||
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
||||
.layout_match_wrap()
|
||||
.align_left()
|
||||
.size(24)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -316,6 +312,7 @@ public class NumberType extends FieldType {
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
//TODO
|
||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ 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.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -103,16 +104,11 @@ public class TallyType extends FieldType {
|
||||
|
||||
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);
|
||||
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
||||
.layout_match_wrap()
|
||||
.align_left()
|
||||
.size(24)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -344,16 +340,12 @@ public class TallyType extends FieldType {
|
||||
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(new TextViewBuilder(parent.getContext(), String.valueOf(view.teamNum))
|
||||
.align_center()
|
||||
.padding(10)
|
||||
.h6()
|
||||
.build());
|
||||
|
||||
|
||||
row.addView(teamNum);
|
||||
row.addView(view);
|
||||
|
||||
parent.addView(row);
|
||||
|
||||
@@ -28,6 +28,7 @@ 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.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -112,15 +113,11 @@ public class TextType extends FieldType {
|
||||
|
||||
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) data.get());
|
||||
tv.setTextSize(18);
|
||||
parent.addView(tv);
|
||||
parent.addView(new TextViewBuilder(parent.getContext(), (String) data.get())
|
||||
.layout_match_wrap()
|
||||
.align_left()
|
||||
.size(18)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -144,25 +141,20 @@ public class TextType extends FieldType {
|
||||
positive_mean = 0;
|
||||
count = 0;
|
||||
|
||||
positive_text = new TextView(parent.getContext());
|
||||
positive_text.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
positive_text.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
positive_text.setTextSize(20);
|
||||
positive_text = new TextViewBuilder(parent.getContext())
|
||||
.align_center()
|
||||
.size(20)
|
||||
.build();
|
||||
|
||||
parent.addView(positive_text);
|
||||
|
||||
for (int i = 0; i < data.length; i++){
|
||||
if (!data[i].isNull()) {
|
||||
SentimentAnalysis.analyse((String) data[i].get(), new SentimentAnalysis.resultCallback() {
|
||||
@Override
|
||||
public void onFinish(float sentiment) {
|
||||
positive_mean += sentiment;
|
||||
count++;
|
||||
SentimentAnalysis.analyse((String) data[i].get(), sentiment -> {
|
||||
positive_mean += sentiment;
|
||||
count++;
|
||||
|
||||
positive_text.setText("Sentiment: " + (positive_mean / count));
|
||||
}
|
||||
positive_text.setText("Sentiment: " + (positive_mean / count));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -228,6 +220,7 @@ public class TextType extends FieldType {
|
||||
|
||||
}
|
||||
|
||||
//TODO
|
||||
public void addDataToTable(TableLayout parent, Map<Integer, List<RawDataType>> data){
|
||||
|
||||
}
|
||||
|
||||
@@ -19,12 +19,9 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.ui.views.FieldBorderedRow;
|
||||
import com.ridgebotics.ridgescout.ui.views.RecyclerList;
|
||||
import com.ridgebotics.ridgescout.ui.views.TeamListOption;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
@@ -47,7 +44,7 @@ public class DataFragment extends Fragment {
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentDataBinding.inflate(inflater, container, false);
|
||||
// binding.table.setStretchAllColumns(true);
|
||||
binding.table.setStretchAllColumns(true);
|
||||
View root = binding.getRoot();
|
||||
|
||||
if(evcode == null || evcode.equals("unset") || event == null){
|
||||
@@ -89,21 +86,35 @@ public class DataFragment extends Fragment {
|
||||
|
||||
public void load_teams(){
|
||||
|
||||
RecyclerList<frcTeam> list = new RecyclerList<>(getContext());
|
||||
binding.table.addView(list);
|
||||
// list.setView
|
||||
int[] teamNums = new int[event.teams.size()];
|
||||
|
||||
list
|
||||
.setup(R.layout.view_team_option, TeamListOption::new)
|
||||
.withLinearLayout()
|
||||
.withDivider()
|
||||
.withItemClickListener((team, position) -> {
|
||||
TeamsFragment.setTeam(team);
|
||||
for(int i = 0 ; i < event.teams.size(); i++){
|
||||
teamNums[i] = event.teams.get(i).teamNumber;
|
||||
}
|
||||
|
||||
Arrays.sort(teamNums);
|
||||
|
||||
for(int i = 0; i < event.teams.size(); i++){
|
||||
frcTeam team = null;
|
||||
for(int a = 0 ; a < event.teams.size(); a++){
|
||||
if(event.teams.get(a).teamNumber == teamNums[i]){
|
||||
team = event.teams.get(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert team != null;
|
||||
|
||||
TeamListOption teamRow = new TeamListOption(getContext());
|
||||
binding.table.addView(teamRow);
|
||||
teamRow.fromTeam(team);
|
||||
|
||||
frcTeam finalTeam = team;
|
||||
teamRow.setOnClickListener(v -> {
|
||||
TeamsFragment.setTeam(finalTeam);
|
||||
((DataParentFragment) getParentFragment()).moveToFragment(new TeamsFragment());
|
||||
// findNavController(this).navigate(R.id.action_navigation_data_parent_to_navigation_data_teams);
|
||||
});
|
||||
|
||||
list.setItems(event.getTeamsSorted());
|
||||
|
||||
}
|
||||
}
|
||||
public void load_fields(){
|
||||
DataManager.reload_match_fields();
|
||||
|
||||
@@ -58,7 +58,7 @@ public class FieldDataFragment extends Fragment {
|
||||
for (int teamIndex = 0; teamIndex < event.teams.size(); teamIndex++) {
|
||||
int teamNum = event.teams.get(teamIndex).teamNumber;
|
||||
List<String> filenames = new ArrayList<>(List.of(FileEditor.getMatchesByTeamNum(evcode, event.teams.get(teamIndex).teamNumber)));
|
||||
filenames.removeAll(rescout_list);
|
||||
filenames.removeAll(rescout_list.get());
|
||||
|
||||
ArrayList<RawDataType> teamData = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ import static com.ridgebotics.ridgescout.utility.DataManager.pit_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_transferValues;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -23,6 +26,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
@@ -30,6 +34,7 @@ import com.ridgebotics.ridgescout.types.data.RawDataType;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -66,38 +71,37 @@ public class TeamsFragment extends Fragment {
|
||||
loadTeam(index);
|
||||
});
|
||||
|
||||
binding.tbaButton.setOnClickListener(v -> openWebPage(
|
||||
"https://www.thebluealliance.com/team/"+team.teamNumber+"/"+SettingsManager.getYearNum()
|
||||
));
|
||||
|
||||
binding.statboticsButton.setOnClickListener(v -> openWebPage(
|
||||
"https://www.statbotics.io/team/"+team.teamNumber+"/"+SettingsManager.getYearNum()
|
||||
));
|
||||
|
||||
loadTeam(SettingsManager.getTeamsDataMode());
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
public void openWebPage(String url) {
|
||||
Uri webpage = Uri.parse(url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
|
||||
// if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
|
||||
startActivity(intent);
|
||||
// }
|
||||
}
|
||||
|
||||
public void loadTeam(int mode) {
|
||||
|
||||
// LinearLayout ll = new LinearLayout(getContext());
|
||||
// ll.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
// ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
// ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
// ));
|
||||
// ll.setOrientation(LinearLayout.VERTICAL);
|
||||
// binding.teamsArea.addView(ll);
|
||||
|
||||
binding.dataTeamCard.fromTeam(team);
|
||||
|
||||
// tv = new TextView(getContext());
|
||||
// tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
// ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
// ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
// ));
|
||||
// tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
// tv.setText(team.getDescription());
|
||||
// tv.setTextSize(16);
|
||||
// ll.addView(tv);
|
||||
|
||||
|
||||
try {add_pit_data(team);}catch(Exception e){AlertManager.error(e);}
|
||||
try {add_match_data(team, mode);}catch(Exception e){AlertManager.error(e);}
|
||||
}
|
||||
|
||||
public void add_pit_data(frcTeam team){
|
||||
public void add_pit_data(frcTeam team) throws BuiltByteParser.byteParsingExeption {
|
||||
binding.pitArea.removeAllViews();
|
||||
final String filename = evcode+"-"+team.teamNumber+".pitscoutdata";
|
||||
|
||||
@@ -117,49 +121,34 @@ public class TeamsFragment extends Fragment {
|
||||
// ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
if(!FileEditor.fileExist(filename)){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("No pit data has been collected!");
|
||||
tv.setTextSize(23);
|
||||
binding.pitArea.addView(tv);
|
||||
binding.pitArea.addView(new TextViewBuilder(getContext(), "No pit data has been collected!")
|
||||
.layout_match_wrap().align_center().size(23).build());
|
||||
return;
|
||||
}
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Pit scouting by " + psda.username);
|
||||
tv.setTextSize(30);
|
||||
binding.pitArea.addView(tv);
|
||||
|
||||
binding.pitArea.addView(new TextViewBuilder(getContext(), "Pit scouting by " + psda.username)
|
||||
.layout_match_wrap()
|
||||
.padding(0, 20, 0, 5)
|
||||
.align_center()
|
||||
.size(30)
|
||||
.build()
|
||||
);
|
||||
|
||||
for (int a = 0; a < psda.data.array.length; a++) {
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(pit_latest_values[a].name);
|
||||
tv.setTextSize(25);
|
||||
TextViewBuilder tvb = new TextViewBuilder(getContext(), pit_latest_values[a].name)
|
||||
.align_center()
|
||||
.layout_match_wrap()
|
||||
.size(25);
|
||||
|
||||
if(psda.data.array[a].isNull()){
|
||||
tv.setBackgroundColor(toggletitle_unselected);
|
||||
tv.setTextColor(toggletitle_black_background);
|
||||
tvb.tv.setBackgroundColor(toggletitle_unselected);
|
||||
tvb.tv.setTextColor(toggletitle_black_background);
|
||||
}
|
||||
|
||||
|
||||
|
||||
binding.pitArea.addView(tv);
|
||||
binding.pitArea.addView(tvb.build());
|
||||
|
||||
|
||||
pit_latest_values[a].add_individual_view(binding.pitArea, psda.data.array[a]);
|
||||
@@ -175,15 +164,11 @@ public class TeamsFragment extends Fragment {
|
||||
String[] files = FileEditor.getMatchesByTeamNum(evcode, team.teamNumber);
|
||||
|
||||
if(files.length == 0){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("No match data has been collected!");
|
||||
tv.setTextSize(23);
|
||||
binding.matchArea.addView(tv);
|
||||
binding.matchArea.addView(new TextViewBuilder(getContext(), "No match data has been collected!")
|
||||
.layout_match_wrap()
|
||||
.align_center()
|
||||
.size(23)
|
||||
.build());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -236,33 +221,27 @@ public class TeamsFragment extends Fragment {
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[matchIndex], match_values, match_transferValues);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 40, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username);
|
||||
tv.setTextSize(30);
|
||||
binding.matchArea.addView(tv);
|
||||
|
||||
TextView title = new TextViewBuilder(getContext(),
|
||||
"M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username)
|
||||
.align_center()
|
||||
.size(30)
|
||||
.padding(0, 0, 40, 5)
|
||||
.build();
|
||||
title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
binding.matchArea.addView(title);
|
||||
|
||||
for (int i = 0; i < psda.data.array.length; i++) {
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(match_latest_values[i].name);
|
||||
tv.setTextSize(25);
|
||||
TextViewBuilder tv = new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||
.align_left()
|
||||
.size(25);
|
||||
|
||||
if (psda.data.array[i].isNull()) {
|
||||
tv.setBackgroundColor(toggletitle_unselected);
|
||||
tv.setTextColor(toggletitle_black_background);
|
||||
tv.tv.setBackgroundColor(toggletitle_unselected);
|
||||
tv.tv.setTextColor(toggletitle_black_background);
|
||||
}
|
||||
|
||||
binding.matchArea.addView(tv);
|
||||
binding.matchArea.addView(tv.build());
|
||||
|
||||
|
||||
if(psda.data.array[i] != null)
|
||||
@@ -294,16 +273,15 @@ public class TeamsFragment extends Fragment {
|
||||
}
|
||||
|
||||
for(int i = 0; i < match_latest_values.length; i++){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(match_latest_values[i].name);
|
||||
tv.setTextSize(30);
|
||||
binding.matchArea.addView(tv);
|
||||
|
||||
binding.matchArea.addView(
|
||||
new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||
.align_center()
|
||||
.padding(0, 0, 20, 5)
|
||||
.size(30)
|
||||
.build()
|
||||
);
|
||||
|
||||
|
||||
if(data[i] != null)
|
||||
match_latest_values[i].add_compiled_view(binding.matchArea, data[i]);
|
||||
@@ -329,19 +307,18 @@ public class TeamsFragment extends Fragment {
|
||||
}
|
||||
|
||||
for(int i = 0; i < match_latest_values.length; i++){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(match_latest_values[i].name);
|
||||
tv.setTextSize(30);
|
||||
|
||||
TextView tv = new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||
.align_center()
|
||||
.size(30)
|
||||
.padding(0,0,20,5)
|
||||
.build();
|
||||
tv.setPaintFlags(tv.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
binding.matchArea.addView(tv);
|
||||
|
||||
if(data[i] != null)
|
||||
match_latest_values[i].add_history_view(binding.matchArea, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -59,11 +60,10 @@ public class EventFragment extends Fragment {
|
||||
add_match_scouting(event);
|
||||
}
|
||||
private void addTableText(TableRow tr, String textStr){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
text.setText(textStr);
|
||||
tr.addView(text);
|
||||
tr.addView(new TextViewBuilder(getContext(), textStr)
|
||||
.align_center()
|
||||
.size(18)
|
||||
.build());
|
||||
}
|
||||
|
||||
public void add_pit_scouting(frcEvent event){
|
||||
@@ -94,33 +94,32 @@ public class EventFragment extends Fragment {
|
||||
tr = new TableRow(getContext());
|
||||
}
|
||||
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
TextViewBuilder text = new TextViewBuilder(getContext(), String.valueOf(num))
|
||||
.size(18)
|
||||
.align_center();
|
||||
|
||||
text.setText(String.valueOf(num));
|
||||
final String filename = event.eventCode + "-" + num + ".pitscoutdata";
|
||||
if(FileEditor.fileExist(filename)){
|
||||
final boolean[] rescout = {DataManager.rescout_list.contains(filename)};
|
||||
|
||||
text.setBackgroundColor(rescout[0] ? color_rescout : color_found);
|
||||
text.tv.setBackgroundColor(rescout[0] ? color_rescout : color_found);
|
||||
|
||||
text.setOnLongClickListener(view -> {
|
||||
text.tv.setOnLongClickListener(view -> {
|
||||
rescout[0] = !rescout[0];
|
||||
if(rescout[0]) {
|
||||
text.setBackgroundColor(color_rescout);
|
||||
text.tv.setBackgroundColor(color_rescout);
|
||||
DataManager.rescout_list.add(filename);
|
||||
}else{
|
||||
text.setBackgroundColor(color_found);
|
||||
text.tv.setBackgroundColor(color_found);
|
||||
DataManager.rescout_list.remove(filename);
|
||||
}
|
||||
DataManager.save_rescout_list();
|
||||
return true;
|
||||
});
|
||||
}else{
|
||||
text.setBackgroundColor(color_not_found);
|
||||
text.tv.setBackgroundColor(color_not_found);
|
||||
}
|
||||
tr.addView(text);
|
||||
tr.addView(text.build());
|
||||
}
|
||||
if(tr != null)
|
||||
binding.teamsTable.addView(tr);
|
||||
@@ -153,10 +152,6 @@ public class EventFragment extends Fragment {
|
||||
addTableText(tr, String.valueOf(match.matchIndex));
|
||||
//
|
||||
for(int i=0;i<6;i++){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
|
||||
int team_num;
|
||||
String alliance_position;
|
||||
|
||||
@@ -168,20 +163,23 @@ public class EventFragment extends Fragment {
|
||||
alliance_position = "blue-"+(i-2);
|
||||
}
|
||||
|
||||
text.setText(String.valueOf(team_num));
|
||||
TextViewBuilder text = new TextViewBuilder(getContext(), String.valueOf(team_num))
|
||||
.size(18)
|
||||
.align_center();
|
||||
|
||||
final String filename = event.eventCode + "-" + match.matchIndex + "-" + alliance_position + "-" + team_num + ".matchscoutdata";
|
||||
if(FileEditor.fileExist(filename)){
|
||||
final boolean[] rescout = {DataManager.rescout_list.contains(filename)};
|
||||
|
||||
text.setBackgroundColor(rescout[0] ? color_rescout : color_found);
|
||||
text.tv.setBackgroundColor(rescout[0] ? color_rescout : color_found);
|
||||
|
||||
text.setOnLongClickListener(view -> {
|
||||
text.tv.setOnLongClickListener(view -> {
|
||||
rescout[0] = !rescout[0];
|
||||
if(rescout[0]) {
|
||||
text.setBackgroundColor(color_rescout);
|
||||
text.tv.setBackgroundColor(color_rescout);
|
||||
DataManager.rescout_list.add(filename);
|
||||
}else{
|
||||
text.setBackgroundColor(color_found);
|
||||
text.tv.setBackgroundColor(color_found);
|
||||
DataManager.rescout_list.remove(filename);
|
||||
}
|
||||
DataManager.save_rescout_list();
|
||||
@@ -189,9 +187,9 @@ public class EventFragment extends Fragment {
|
||||
});
|
||||
|
||||
}else{
|
||||
text.setBackgroundColor(color_not_found);
|
||||
text.tv.setBackgroundColor(color_not_found);
|
||||
}
|
||||
tr.addView(text);
|
||||
tr.addView(text.build());
|
||||
}
|
||||
|
||||
binding.matchTable.addView(tr);
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.divider.MaterialDivider;
|
||||
import com.ridgebotics.ridgescout.ui.views.ToggleTitleView;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingMatchBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
@@ -32,6 +33,7 @@ import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.AutoSaveManager;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
// Fragment for match scouting data editing.
|
||||
public class MatchScoutingFragment extends Fragment {
|
||||
@@ -58,10 +60,12 @@ public class MatchScoutingFragment extends Fragment {
|
||||
binding.matchTeamCard.setVisibility(View.VISIBLE);
|
||||
|
||||
if(DataManager.match_values == null || DataManager.match_values.length == 0){
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText("Failed to load fields.\nTry to either download or create match scouting fields.");
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
binding.MatchScoutArea.addView(tv);
|
||||
|
||||
binding.MatchScoutArea.addView(
|
||||
new TextViewBuilder(getContext(), "Failed to load fields.\nTry to either download or create match scouting fields.")
|
||||
.align_center()
|
||||
.build());
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@@ -347,7 +351,7 @@ public class MatchScoutingFragment extends Fragment {
|
||||
|
||||
|
||||
|
||||
public void get_fields(){
|
||||
public void get_fields() throws BuiltByteParser.byteParsingExeption{
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues);
|
||||
RawDataType[] types = psdr.data.array;
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.android.material.divider.MaterialDivider;
|
||||
import com.ridgebotics.ridgescout.ui.views.PitScoutingIndicator;
|
||||
import com.ridgebotics.ridgescout.ui.views.ToggleTitleView;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
@@ -224,7 +225,7 @@ public class PitScoutingFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
public void get_fields(){
|
||||
public void get_fields() throws BuiltByteParser.byteParsingExeption{
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||
RawDataType[] types = psdr.data.array;
|
||||
|
||||
@@ -51,89 +51,89 @@ public class PitSelectorFragment extends Fragment {
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
// load_teams();
|
||||
load_teams();
|
||||
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
// public void load_teams(){
|
||||
//// binding.pitFileIndicator.setVisibility(View.GONE);
|
||||
//// binding.pitTeamName.setVisibility(View.GONE);
|
||||
//// binding.pitTeamDescription.setVisibility(View.GONE);
|
||||
////
|
||||
//// clear_fields();
|
||||
public void load_teams(){
|
||||
// binding.pitFileIndicator.setVisibility(View.GONE);
|
||||
// binding.pitTeamName.setVisibility(View.GONE);
|
||||
// binding.pitTeamDescription.setVisibility(View.GONE);
|
||||
//
|
||||
//
|
||||
// int[] teamNums = new int[event.teams.size()];
|
||||
//
|
||||
// for(int i = 0 ; i < event.teams.size(); i++){
|
||||
// teamNums[i] = event.teams.get(i).teamNumber;
|
||||
// }
|
||||
//
|
||||
// Arrays.sort(teamNums);
|
||||
//
|
||||
// TableLayout table = new TableLayout(getContext());
|
||||
// table.setStretchAllColumns(true);
|
||||
// binding.teams.addView(table);
|
||||
//
|
||||
//
|
||||
// for(int i = 0; i < event.teams.size(); i++){
|
||||
// frcTeam team = null;
|
||||
// for(int a = 0 ; a < event.teams.size(); a++){
|
||||
// if(event.teams.get(a).teamNumber == teamNums[i]){
|
||||
// team = event.teams.get(a);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// assert team != null;
|
||||
//
|
||||
//// TableRow tr = new TableRow(getContext());
|
||||
//// TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
//// FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
//// FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
//// );
|
||||
//// rowParams.setMargins(20,20,20,20);
|
||||
//// tr.setLayoutParams(rowParams);
|
||||
//// tr.setPadding(20,20,20,20);
|
||||
//// table.addView(tr);
|
||||
//
|
||||
// TeamListOption teamRow = new TeamListOption(getContext());
|
||||
// table.addView(teamRow);
|
||||
// teamRow.fromTeam(team);
|
||||
//
|
||||
//
|
||||
// String filename = evcode + "-" + team.teamNumber + ".pitscoutdata";
|
||||
//
|
||||
// if (FileEditor.fileExist(filename)) {
|
||||
// final boolean[] rescout = {DataManager.rescout_list.contains(filename)};
|
||||
//
|
||||
// teamRow.setColor(DataManager.rescout_list.contains(filename) ? color_rescout : color_found);
|
||||
//
|
||||
// teamRow.setOnLongClickListener(v -> {
|
||||
// rescout[0] = !rescout[0];
|
||||
// if(rescout[0]){
|
||||
// DataManager.rescout_list.add(filename);
|
||||
// teamRow.setColor(color_rescout);
|
||||
// DataManager.save_rescout_list();
|
||||
// }else{
|
||||
// DataManager.rescout_list.remove(filename);
|
||||
// teamRow.setColor(color_found);
|
||||
// DataManager.save_rescout_list();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return true;
|
||||
// });
|
||||
// } else {
|
||||
// teamRow.setColor(color_not_found);
|
||||
// teamRow.setOnLongClickListener(v -> true);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// frcTeam finalTeam = team;
|
||||
// teamRow.setOnClickListener(v -> onSelect.onSelect(this, finalTeam));
|
||||
// }
|
||||
// }
|
||||
// clear_fields();
|
||||
|
||||
|
||||
int[] teamNums = new int[event.teams.size()];
|
||||
|
||||
for(int i = 0 ; i < event.teams.size(); i++){
|
||||
teamNums[i] = event.teams.get(i).teamNumber;
|
||||
}
|
||||
|
||||
Arrays.sort(teamNums);
|
||||
|
||||
TableLayout table = new TableLayout(getContext());
|
||||
table.setStretchAllColumns(true);
|
||||
binding.teams.addView(table);
|
||||
|
||||
|
||||
for(int i = 0; i < event.teams.size(); i++){
|
||||
frcTeam team = null;
|
||||
for(int a = 0 ; a < event.teams.size(); a++){
|
||||
if(event.teams.get(a).teamNumber == teamNums[i]){
|
||||
team = event.teams.get(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert team != null;
|
||||
|
||||
// TableRow tr = new TableRow(getContext());
|
||||
// TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
|
||||
// FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
// FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
// );
|
||||
// rowParams.setMargins(20,20,20,20);
|
||||
// tr.setLayoutParams(rowParams);
|
||||
// tr.setPadding(20,20,20,20);
|
||||
// table.addView(tr);
|
||||
|
||||
TeamListOption teamRow = new TeamListOption(getContext());
|
||||
table.addView(teamRow);
|
||||
teamRow.fromTeam(team);
|
||||
|
||||
|
||||
String filename = evcode + "-" + team.teamNumber + ".pitscoutdata";
|
||||
|
||||
if (FileEditor.fileExist(filename)) {
|
||||
final boolean[] rescout = {DataManager.rescout_list.contains(filename)};
|
||||
|
||||
teamRow.setColor(DataManager.rescout_list.contains(filename) ? color_rescout : color_found);
|
||||
|
||||
teamRow.setOnLongClickListener(v -> {
|
||||
rescout[0] = !rescout[0];
|
||||
if(rescout[0]){
|
||||
DataManager.rescout_list.add(filename);
|
||||
teamRow.setColor(color_rescout);
|
||||
DataManager.save_rescout_list();
|
||||
}else{
|
||||
DataManager.rescout_list.remove(filename);
|
||||
teamRow.setColor(color_found);
|
||||
DataManager.save_rescout_list();
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
teamRow.setColor(color_not_found);
|
||||
teamRow.setOnLongClickListener(v -> true);
|
||||
}
|
||||
|
||||
|
||||
frcTeam finalTeam = team;
|
||||
teamRow.setOnClickListener(v -> onSelect.onSelect(this, finalTeam));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingBinding;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
@@ -156,29 +157,35 @@ public class ScoutingFragment extends Fragment {
|
||||
private void updateDashboard() {
|
||||
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());
|
||||
|
||||
TextView nextMatchText = new TextView(getContext());
|
||||
nextMatchText.setText("Our next match: Match " + nextMatch);
|
||||
nextMatchText.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body1);
|
||||
binding.infoBox.addView(nextMatchText);
|
||||
if(event.matches.size() == 0) {
|
||||
binding.textMatchAlliance.setText("No Matches!");
|
||||
} else {
|
||||
int teamNum = SettingsManager.getTeamNum();
|
||||
int curMatchNum = SettingsManager.getMatchNum();
|
||||
|
||||
int informedBy = event.getMostInformedBy(teamNum, curMatchNum);
|
||||
binding.textMatchAlliance.setText("Match: " + (curMatchNum+1) + ", " + SettingsManager.getAllyPos());
|
||||
|
||||
TextView mostInformedText = new TextView(getContext());
|
||||
mostInformedText.setText("Most informed by: Match " + informedBy);
|
||||
mostInformedText.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body1);
|
||||
binding.infoBox.addView(mostInformedText);
|
||||
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)
|
||||
.body1()
|
||||
.build());
|
||||
|
||||
int informedBy = event.getMostInformedBy(teamNum, curMatchNum);
|
||||
|
||||
|
||||
binding.infoBox.addView(new TextViewBuilder(getContext(), "Most informed by: Match " + informedBy)
|
||||
.body1()
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ 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.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.UUID;
|
||||
@@ -397,11 +398,11 @@ public class FieldEditorHelper {
|
||||
this.t = t;
|
||||
views = new View[types.length];
|
||||
for(int i = 0; i < types.length; i++){
|
||||
TextView tv = new TextView(c);
|
||||
tv.setText(types[i].name);
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
tv.setTextSize(20);
|
||||
parentView.addView(tv);
|
||||
|
||||
parentView.addView(new TextViewBuilder(c, types[i].name)
|
||||
.align_center()
|
||||
.size(20)
|
||||
.build());
|
||||
|
||||
views[i] = createEdit(c, types[i]);
|
||||
parentView.addView(views[i]);
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.ridgebotics.ridgescout.types.input.FieldType;
|
||||
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
||||
import com.ridgebotics.ridgescout.ui.views.FieldDisplay;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -196,10 +197,9 @@ public class FieldsFragment extends Fragment {
|
||||
|
||||
sv.addView(table);
|
||||
|
||||
TextView UUID = new TextView(getContext());
|
||||
UUID.setText("Type: " + field.get_type_name() + "\nUUID: " + field.UUID);
|
||||
|
||||
table.addView(UUID);
|
||||
table.addView(new TextViewBuilder(getContext(), "Type: " + field.get_type_name() + "\nUUID: " + field.UUID)
|
||||
.build());
|
||||
|
||||
FieldEditorHelper f = new FieldEditorHelper(getContext(), field, table);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.ridgebotics.ridgescout.ui.settings;
|
||||
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.LinearLayout.HORIZONTAL;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||
@@ -21,6 +20,9 @@ import static com.ridgebotics.ridgescout.utility.SettingsManager.prefs;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
@@ -29,12 +31,9 @@ import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -51,11 +50,11 @@ import com.ridgebotics.ridgescout.databinding.FragmentSettingsBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.Fields;
|
||||
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
||||
import com.ridgebotics.ridgescout.ui.views.TallyCounterView;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
|
||||
import org.w3c.dom.Text;
|
||||
import com.ridgebotics.ridgescout.utility.ToDelete;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -86,9 +85,19 @@ public class SettingsFragment extends Fragment {
|
||||
SettingsManager manager = new SettingsManager(getContext());
|
||||
|
||||
|
||||
ButtonSettingsItem appInfoButton = new ButtonSettingsItem();
|
||||
appInfoButton.addButton("App info", v -> showAppInfo());
|
||||
manager.addItem(appInfoButton);
|
||||
|
||||
|
||||
ButtonSettingsItem corruptButton = new ButtonSettingsItem();
|
||||
corruptButton.addButton("Remove corrupted files", view -> {});
|
||||
corruptButton.addButton("find corrupted files", view -> {
|
||||
ToDelete.findCorruptedFiles(getContext());
|
||||
});
|
||||
corruptButton.addButton("delete files", view -> {
|
||||
ToDelete.deleteFiles(getContext(), Arrays.asList(FileEditor.getFiles()), false);
|
||||
});
|
||||
// corruptButton.setEnabled(!getEVCode().equals("unset"));
|
||||
|
||||
manager.addItem(corruptButton);
|
||||
manager.addItem(new HeaderSettingsItem("Advanced"));
|
||||
@@ -143,6 +152,8 @@ public class SettingsFragment extends Fragment {
|
||||
|
||||
manager.addItem(new CheckboxSettingsItem(EnableQuickAllianceChangeKey, "Enable quick alliance swap", null));
|
||||
manager.addItem(new DropdownSettingsItem(FieldImageKey, "Field Image", new String[]{
|
||||
"2026",
|
||||
"2026 (Flipped)",
|
||||
"2025",
|
||||
"2025 (Flipped)"
|
||||
}));
|
||||
@@ -244,6 +255,41 @@ public class SettingsFragment extends Fragment {
|
||||
|
||||
|
||||
|
||||
private TextView createText(String title) {
|
||||
return new TextViewBuilder(getContext(), title)
|
||||
.body1().build();
|
||||
}
|
||||
|
||||
private void showAppInfo() {
|
||||
LinearLayout ll = new LinearLayout(getContext());
|
||||
ll.setOrientation(VERTICAL);
|
||||
ll.setPadding(10, 10, 10, 10);
|
||||
|
||||
try {
|
||||
PackageInfo pInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0);
|
||||
ll.addView(createText("Package: " + pInfo.packageName));
|
||||
ll.addView(createText("Version: " + pInfo.versionName));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
ll.addView(createText("Signature: " + (pInfo.signingInfo != null ? "True" : "False")));
|
||||
}
|
||||
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
AlertManager.error("Failed to get version info", e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||
alert.setTitle("App info");
|
||||
alert.setView(ll);
|
||||
alert.setNeutralButton("Ok", null);
|
||||
alert.setCancelable(true);
|
||||
|
||||
alert.create().show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -350,9 +396,8 @@ public class SettingsFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View createView(Context context) {
|
||||
TextView titleView = new TextView(context);
|
||||
titleView.setText(getTitle());
|
||||
titleView.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1);
|
||||
TextView titleView = new TextViewBuilder(context, getTitle())
|
||||
.sub1().build();
|
||||
|
||||
TextInputLayout textInputLayout = new TextInputLayout(context);
|
||||
editText = new TextInputEditText(context);
|
||||
@@ -432,11 +477,10 @@ public class SettingsFragment extends Fragment {
|
||||
});
|
||||
tally.setEnabled(enabled);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText(getTitle());
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6);
|
||||
tv.setGravity(Gravity.CENTER);
|
||||
ll.addView(tv);
|
||||
|
||||
ll.addView(new TextViewBuilder(getContext(), getTitle())
|
||||
.h6()
|
||||
.build());
|
||||
|
||||
ll.addView(tally);
|
||||
|
||||
@@ -560,10 +604,9 @@ public class SettingsFragment extends Fragment {
|
||||
ll.setOrientation(VERTICAL);
|
||||
ll.setPadding(0, 20,0,0);
|
||||
|
||||
TextView tv = new TextView(context);
|
||||
tv.setText(title);
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline4);
|
||||
ll.addView(tv);
|
||||
ll.addView(new TextViewBuilder(context, title)
|
||||
.h4()
|
||||
.build());
|
||||
|
||||
ll.addView(new MaterialDivider(context));
|
||||
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.FileEditor.baseDir;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
|
||||
import org.apache.commons.net.ftp.FTP;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
// This is now deprecated. use HTTPSync
|
||||
// Class to synchronise data over FTP.
|
||||
public class FTPSync extends Thread {
|
||||
public static final String remoteBasePath = "/RidgeScout/";
|
||||
public static final String timestampsFilename = "timestamps";
|
||||
|
||||
|
||||
|
||||
public static long lastSyncTime = 0;
|
||||
private static Date curSyncTime;
|
||||
private static final long millisTolerance = 1000;
|
||||
|
||||
private boolean after(Date a, Date b){
|
||||
return a.getTime() - b.getTime() > millisTolerance;
|
||||
}
|
||||
|
||||
|
||||
public interface onResult {
|
||||
void onResult(boolean error, int upCount, int downCount);
|
||||
}
|
||||
public interface UpdateIndicator {
|
||||
void onText(String text);
|
||||
}
|
||||
private static UpdateIndicator updateIndicator = text -> {};
|
||||
public static String text = "";
|
||||
private static void setUpdateIndicator(String m_text){
|
||||
text = m_text;
|
||||
updateIndicator.onText(m_text);
|
||||
}
|
||||
public static void setOnUpdateIndicator(UpdateIndicator m_updateIndicator){
|
||||
updateIndicator = m_updateIndicator;
|
||||
}
|
||||
|
||||
private static onResult onResult = (error, upCount, downCount) -> {};
|
||||
public static void setOnResult(onResult result){
|
||||
onResult = result;
|
||||
}
|
||||
|
||||
private static boolean isRunning = false;
|
||||
public static boolean getIsRunning(){return isRunning;}
|
||||
|
||||
public static void sync(){
|
||||
// DataManager.reload_event();
|
||||
FTPSync ftpSync = new FTPSync();
|
||||
|
||||
curSyncTime = new Date();
|
||||
|
||||
ftpSync.start();
|
||||
}
|
||||
|
||||
FTPClient ftpClient;
|
||||
|
||||
private int upCount = 0;
|
||||
private int downCount = 0;
|
||||
|
||||
private void downloadFile(String remoteFile, File localFile) throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(localFile)) {
|
||||
ftpClient.retrieveFile(remoteBasePath + remoteFile, fos);
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadFile(File localFile) throws IOException {
|
||||
try (FileInputStream fis = new FileInputStream(localFile)) {
|
||||
ftpClient.storeFile(remoteBasePath + localFile.getName(), fis);
|
||||
}
|
||||
}
|
||||
|
||||
private FTPFile findRemoteFile(FTPFile[] remoteFiles, String fileName) {
|
||||
for (FTPFile file : remoteFiles) {
|
||||
if (file.getName().equals(fileName)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Date getUtcTimestamp(FTPFile file) {
|
||||
return file.getTimestamp().getTime();
|
||||
}
|
||||
|
||||
private Date getLocalFileUtcTimestamp(File file) {
|
||||
return new Date(file.lastModified());
|
||||
}
|
||||
|
||||
private void setLocalFileTimestamp(File file, Date date) {
|
||||
file.setLastModified(date.getTime());
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
isRunning = true;
|
||||
boolean sendMetaFiles = SettingsManager.getFTPSendMetaFiles();
|
||||
|
||||
// Meta files
|
||||
List<String> meta_string_array = Arrays.asList(
|
||||
"matches.fields",
|
||||
"pits.fields",
|
||||
evcode+".eventdata"
|
||||
);
|
||||
|
||||
try {
|
||||
// Login to FTP
|
||||
ftpClient = new FTPClient();
|
||||
InetAddress address = InetAddress.getByName(SettingsManager.getFTPServer());
|
||||
ftpClient.connect(address);
|
||||
ftpClient.login("anonymous", null);
|
||||
ftpClient.enterLocalPassiveMode();
|
||||
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
|
||||
|
||||
File localDir = new File(baseDir);
|
||||
File[] localFiles = localDir.listFiles();
|
||||
Map<String, Date> remoteTimestamps = getTimestamps();
|
||||
|
||||
// Loop through local files and send all that are more recent
|
||||
if (localFiles != null) {
|
||||
for (int i = 0; i < localFiles.length; i++) {
|
||||
File localFile = localFiles[i];
|
||||
setUpdateIndicator("Uploading " + (i+1) + "/" + localFiles.length);
|
||||
|
||||
if(localFile.isDirectory()) continue;
|
||||
// Remove timestamts file
|
||||
if(localFile.getName().equals(timestampsFilename)) continue;
|
||||
// Remove meta files if the option is disabled
|
||||
if(!sendMetaFiles && meta_string_array.contains(localFile.getName())) continue;
|
||||
|
||||
Date remoteTimestamp = remoteTimestamps.get(localFile.getName());
|
||||
|
||||
Date localTimeStamp = getLocalFileUtcTimestamp(localFile);
|
||||
|
||||
if (remoteTimestamp == null || after(localTimeStamp, remoteTimestamp)) {
|
||||
uploadFile(localFile);
|
||||
Log.i(getClass().toString(), "Uploaded" + localFile.getName());
|
||||
|
||||
setLocalFileTimestamp(localFile, curSyncTime);
|
||||
remoteTimestamps.put(localFile.getName(), curSyncTime);
|
||||
upCount++;
|
||||
}else{
|
||||
Log.i(getClass().toString(), "Did not upload");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> keySet = remoteTimestamps.keySet();
|
||||
Iterator<String> keyIt = keySet.iterator();
|
||||
for (int i = 0; i < keySet.size(); i++) {
|
||||
String remoteFile = keyIt.next();
|
||||
setUpdateIndicator("Downloading " + (i+1) + "/" + keySet.size());
|
||||
|
||||
File localFile = new File(baseDir, remoteFile);
|
||||
if(remoteFile.equals(timestampsFilename)) continue;
|
||||
// Remove meta files if the option is disabled
|
||||
if(!sendMetaFiles && meta_string_array.contains(remoteFile)) continue;
|
||||
|
||||
// Date t1 = getLocalFileUtcTimestamp(localFile);
|
||||
// Date t2 = getUtcTimestamp(remoteFile);
|
||||
////
|
||||
// System.out.println("- " + t1 + (t1.after(t2) ? ">" : "<") + t2);
|
||||
|
||||
Date localTimeStamp = getLocalFileUtcTimestamp(localFile);
|
||||
Date remoteTimestamp = remoteTimestamps.get(remoteFile);
|
||||
|
||||
|
||||
|
||||
if (!localFile.exists() || (after(remoteTimestamp, localTimeStamp) && !localTimeStamp.equals(remoteTimestamp))) {
|
||||
downloadFile(remoteFile, localFile);
|
||||
|
||||
Log.i(getClass().toString(), "Downloaded " + localFile.getName());
|
||||
|
||||
if(!localFile.exists()) Log.i(getClass().toString(), "Not exist");
|
||||
else if(after(remoteTimestamp, localTimeStamp)) Log.i(getClass().toString(), "Before: " + (localTimeStamp.getTime()-remoteTimestamp.getTime()));
|
||||
|
||||
// Date d = getUtcTimestamp(remoteFile);
|
||||
setLocalFileTimestamp(localFile, remoteTimestamps.get(localFile.getName()));
|
||||
// remoteTimestamps.put(remoteFile, curSyncTime);
|
||||
downCount++;
|
||||
}else{
|
||||
Log.i(getClass().toString(), "Did not download");
|
||||
}
|
||||
}
|
||||
|
||||
setTimestamps(remoteTimestamps);
|
||||
|
||||
} catch (Exception e) {
|
||||
AlertManager.error("Failed Syncing!", e);
|
||||
onResult.onResult(true, upCount, downCount);
|
||||
setUpdateIndicator("ERROR!");
|
||||
} finally {
|
||||
onResult.onResult(false, upCount, downCount);
|
||||
setUpdateIndicator("Finished");
|
||||
}
|
||||
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
private boolean setTimestamps(Map<String, Date> timestamps){
|
||||
try {
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
String[] filenames = timestamps.keySet().toArray(new String[0]);
|
||||
|
||||
for(int i = 0; i < filenames.length; i++){
|
||||
bb.addString(filenames[i]);
|
||||
bb.addLong(timestamps.get(filenames[i]).getTime());
|
||||
}
|
||||
|
||||
FileEditor.writeFile(timestampsFilename, bb.build());
|
||||
|
||||
uploadFile(new File(baseDir + timestampsFilename));
|
||||
return true;
|
||||
} catch (ByteBuilder.buildingException | IOException e) {
|
||||
AlertManager.error("Failed Syncing!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Date> getTimestamps() {
|
||||
try {
|
||||
downloadFile(timestampsFilename, new File(baseDir + timestampsFilename));
|
||||
|
||||
byte[] data = FileEditor.readFile(timestampsFilename);
|
||||
|
||||
if(data == null || data.length == 0)
|
||||
return new HashMap<>();
|
||||
|
||||
BuiltByteParser bbp = new BuiltByteParser(data);
|
||||
List<BuiltByteParser.parsedObject> pa = bbp.parse();
|
||||
|
||||
Map<String, Date> output = new HashMap<>();
|
||||
for(int i = 0; i < pa.size(); i+=2){
|
||||
// System.out.println((long) pa.get(i).get());
|
||||
output.put(
|
||||
(String) pa.get(i).get(),
|
||||
new Date((long) pa.get(i+1).get())
|
||||
);
|
||||
}
|
||||
return output;
|
||||
|
||||
}catch (IOException | BuiltByteParser.byteParsingExeption e){
|
||||
AlertManager.error("Failed Syncing!", e);
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -49,7 +50,10 @@ public class FileSelectorFragment extends Fragment {
|
||||
meta_string_array = new String[]{
|
||||
"matches.fields",
|
||||
"pits.fields",
|
||||
evcode+".eventdata"
|
||||
evcode+".eventdata",
|
||||
evcode+".rescout",
|
||||
evcode+".scoutnotice",
|
||||
"todelete.colabarray",
|
||||
};
|
||||
|
||||
String[] files = FileEditor.getEventFiles(evcode);
|
||||
@@ -74,10 +78,12 @@ public class FileSelectorFragment extends Fragment {
|
||||
checkBox.setChecked(true);
|
||||
tr.addView(checkBox);
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText(String.valueOf(files[i]));
|
||||
tv.setTextSize(20);
|
||||
tr.addView(tv);
|
||||
// Filename
|
||||
tr.addView(
|
||||
new TextViewBuilder(getContext(), files[i])
|
||||
.size(20)
|
||||
.build()
|
||||
);
|
||||
|
||||
final int fi = i;
|
||||
tr.setOnClickListener(view -> {
|
||||
|
||||
@@ -4,14 +4,14 @@ import static com.ridgebotics.ridgescout.utility.FileEditor.baseDir;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.ColabArray;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.HttpGetFile;
|
||||
import com.ridgebotics.ridgescout.utility.HttpPutFile;
|
||||
import com.ridgebotics.ridgescout.utility.RequestTask;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.utility.ToDelete;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -23,10 +23,8 @@ import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -100,6 +98,10 @@ public class HttpSync extends Thread {
|
||||
public void run() {
|
||||
isRunning = true;
|
||||
boolean sendMetaFiles = SettingsManager.getFTPSendMetaFiles();
|
||||
|
||||
ToDelete.reload_todelete_list();
|
||||
List<String> removeFiles = ToDelete.todelete_list.get();
|
||||
|
||||
String serverIP = SettingsManager.getFTPServer();
|
||||
String serverKey = SettingsManager.getFTPKey();
|
||||
|
||||
@@ -117,6 +119,9 @@ public class HttpSync extends Thread {
|
||||
|
||||
getLocalFileMetadata();
|
||||
|
||||
localFiles.removeIf(localFile -> removeFiles.contains(localFile.filename+","+localFile.checksum));
|
||||
remoteFiles.removeIf(remoteFile -> removeFiles.contains(remoteFile.filename+","+remoteFile.checksum));
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -129,23 +134,30 @@ public class HttpSync extends Thread {
|
||||
|
||||
TransferFile remoteFile = findInFileArray(remoteFiles, localFile.filename);
|
||||
|
||||
// Check if the file is a meta file, and uploads it based off of the setting
|
||||
boolean sendField = (sendMetaFiles || !(localFile.filename.endsWith(".fields")));
|
||||
|
||||
boolean shouldUpload;
|
||||
boolean special;
|
||||
|
||||
if(
|
||||
(
|
||||
sendMetaFiles || !(
|
||||
localFile.filename.endsWith(".fields")
|
||||
)
|
||||
// If there is no file on the sever, upload.
|
||||
if(remoteFile == null) {
|
||||
shouldUpload = true;
|
||||
special = false;
|
||||
}
|
||||
else {
|
||||
// If the remote file is the same as the local one, do nothing.
|
||||
boolean checksumsEqual = Objects.equals(localFile.checksum, remoteFile.checksum);
|
||||
// If the local file is a colabarray, give it a special propreties
|
||||
special = FileEditor.requiresSpecialInteraction(remoteFile.filename);
|
||||
// If the local file is updated after the remote file
|
||||
boolean after = after(localFile.updated, remoteFile.updated);
|
||||
|
||||
)
|
||||
&& (remoteFile == null ||
|
||||
(
|
||||
!Objects.equals(localFile.checksum, remoteFile.checksum) &&
|
||||
after(localFile.updated, remoteFile.updated)
|
||||
)
|
||||
)) {
|
||||
uploadFile(localFile, serverIP, serverKey);
|
||||
// await();
|
||||
shouldUpload = !checksumsEqual && (special || after);
|
||||
}
|
||||
|
||||
if(sendField && shouldUpload) {
|
||||
uploadFile(localFile, serverIP, serverKey, special);
|
||||
Log.d(getClass().toString(), "LocalFile: " + localFile.filename + ", " + localFile.checksum + ", " + localFile.updated + ": Uploaded");
|
||||
upCount++;
|
||||
}else {
|
||||
@@ -162,13 +174,24 @@ public class HttpSync extends Thread {
|
||||
|
||||
TransferFile localFile = findInFileArray(localFiles, remoteFile.filename);
|
||||
|
||||
if(localFile == null ||
|
||||
(
|
||||
!Objects.equals(localFile.checksum, remoteFile.checksum) &&
|
||||
after(remoteFile.updated, localFile.updated) &&
|
||||
!localFile.updated.equals(remoteFile.updated)
|
||||
)
|
||||
) {
|
||||
boolean shouldDownload;
|
||||
|
||||
// If there is no file on the sever, upload.
|
||||
if(localFile == null) {
|
||||
shouldDownload = true;
|
||||
} else {
|
||||
// If the remote file is the same as the local one, do nothing.
|
||||
|
||||
boolean checksumsNotEqual = !Objects.equals(localFile.checksum, remoteFile.checksum);
|
||||
// If the local file is updated after the remote file
|
||||
boolean after = after(remoteFile.updated, localFile.updated);
|
||||
// If the local file and remote file's upload dates are exactly the same
|
||||
boolean datesNotEqual = !localFile.updated.equals(remoteFile.updated);
|
||||
|
||||
shouldDownload = checksumsNotEqual && after;
|
||||
}
|
||||
|
||||
if(shouldDownload) {
|
||||
downloadFile(remoteFile, serverIP);
|
||||
// await();
|
||||
Log.d(getClass().toString(), "RemoteFile: " + remoteFile.filename + ", " + remoteFile.checksum + ", " + remoteFile.updated + ": Downloaded");
|
||||
@@ -181,8 +204,8 @@ public class HttpSync extends Thread {
|
||||
setUpdateIndicator("Downloading " + (Math.floor((double) (i * 1000) / remoteFiles.size()) / 10) + "%");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Remove files marked for deletion
|
||||
ToDelete.deleteFiles();
|
||||
|
||||
setUpdateIndicator("Finished, " + upCount + " Up, " + downCount + " Down");
|
||||
|
||||
@@ -192,6 +215,7 @@ public class HttpSync extends Thread {
|
||||
}
|
||||
|
||||
|
||||
// Find file based off of filename
|
||||
private TransferFile findInFileArray(List<TransferFile> files, String filename){
|
||||
for(TransferFile file : files) {
|
||||
if(file.filename.equals(filename))
|
||||
@@ -200,29 +224,12 @@ public class HttpSync extends Thread {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get teh last modified date of a file
|
||||
private Date getLocalFileUtcTimestamp(File file) {
|
||||
return new Date(file.lastModified());
|
||||
}
|
||||
|
||||
public static String getSHA256Hash(String filePath) throws IOException, NoSuchAlgorithmException {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
FileInputStream fis = new FileInputStream(filePath);
|
||||
byte[] byteArray = new byte[1024];
|
||||
int bytesCount = 0;
|
||||
|
||||
while ((bytesCount = fis.read(byteArray)) != -1) {
|
||||
digest.update(byteArray, 0, bytesCount);
|
||||
}
|
||||
fis.close();
|
||||
|
||||
byte[] bytes = digest.digest();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// Load the local metadata of files
|
||||
private void getLocalFileMetadata() {
|
||||
File localDir = new File(baseDir);
|
||||
File[] localFileNames = localDir.listFiles();
|
||||
@@ -239,9 +246,10 @@ public class HttpSync extends Thread {
|
||||
tf.filename = file.getName();
|
||||
tf.updated = getLocalFileUtcTimestamp(file);
|
||||
try {
|
||||
tf.checksum = getSHA256Hash(file.getPath());
|
||||
tf.checksum = FileEditor.getSHA256Hash(file.getName());
|
||||
} catch (Exception e) {
|
||||
|
||||
AlertManager.error("Failed to get hash of: " + file.getName(), e);
|
||||
continue;
|
||||
}
|
||||
localFiles.add(tf);
|
||||
}
|
||||
@@ -277,90 +285,100 @@ public class HttpSync extends Thread {
|
||||
await();
|
||||
}
|
||||
|
||||
|
||||
// private boolean setTimestamps(Map<String, Date> timestamps){
|
||||
// try {
|
||||
// ByteBuilder bb = new ByteBuilder();
|
||||
// String[] filenames = timestamps.keySet().toArray(new String[0]);
|
||||
//
|
||||
// for(int i = 0; i < filenames.length; i++){
|
||||
// bb.addString(filenames[i]);
|
||||
// bb.addLong(timestamps.get(filenames[i]).getTime());
|
||||
// }
|
||||
//
|
||||
// FileEditor.writeFile(timestampsFilename, bb.build());
|
||||
//
|
||||
// uploadFile(new File(baseDir + timestampsFilename));
|
||||
// return true;
|
||||
// } catch (ByteBuilder.buildingException | IOException e) {
|
||||
// AlertManager.error("Failed Syncing!", e);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private Map<String, Date> getTimestamps() {
|
||||
// try {
|
||||
// downloadFile(timestampsFilename, new File(baseDir + timestampsFilename));
|
||||
//
|
||||
// byte[] data = FileEditor.readFile(timestampsFilename);
|
||||
//
|
||||
// if(data == null || data.length == 0)
|
||||
// return new HashMap<>();
|
||||
//
|
||||
// BuiltByteParser bbp = new BuiltByteParser(data);
|
||||
// List<BuiltByteParser.parsedObject> pa = bbp.parse();
|
||||
//
|
||||
// Map<String, Date> output = new HashMap<>();
|
||||
// for(int i = 0; i < pa.size(); i+=2){
|
||||
//// System.out.println((long) pa.get(i).get());
|
||||
// output.put(
|
||||
// (String) pa.get(i).get(),
|
||||
// new Date((long) pa.get(i+1).get())
|
||||
// );
|
||||
// }
|
||||
// return output;
|
||||
//
|
||||
// }catch (IOException | BuiltByteParser.byteParsingExeption e){
|
||||
// AlertManager.error("Failed Syncing!", e);
|
||||
// return new HashMap<>();
|
||||
// }
|
||||
// }
|
||||
void uploadFile(TransferFile tf, String serverURL, String apiKey) {
|
||||
// Create HTTP request to upload file
|
||||
void uploadFile(TransferFile tf, String serverURL, String apiKey, boolean special) {
|
||||
runningRequest.set(false);
|
||||
HttpPutFile uploadTask = new HttpPutFile(serverURL + "/api/" + tf.filename, new File(baseDir + tf.filename), new HttpPutFile.UploadCallback() {
|
||||
@Override
|
||||
public void onResult(String error) {
|
||||
if(error != null)
|
||||
|
||||
|
||||
// If the file is "special", download the server copy and merge the local and remote ColabArrays
|
||||
if(special) {
|
||||
HttpGetFile getTask = new HttpGetFile(serverURL + "/api/" + tf.filename, new File(baseDir + tf.filename), (stream, error) -> {
|
||||
if(error != null) {
|
||||
AlertManager.error(error);
|
||||
return;
|
||||
} else if (stream == null) {
|
||||
AlertManager.error("Output stream from download was null!");
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] bytes = stream.toByteArray();
|
||||
|
||||
FileEditor.syncColabArray(
|
||||
tf.filename,
|
||||
FileEditor.readFile(tf.filename),
|
||||
bytes
|
||||
);
|
||||
|
||||
|
||||
HttpPutFile uploadTask = new HttpPutFile(serverURL + "/api/" + tf.filename, new File(baseDir + tf.filename), error2 -> {
|
||||
if (error2 != null)
|
||||
AlertManager.error(error2);
|
||||
runningRequest.set(true);
|
||||
}, new String[]{
|
||||
"api_key: " + apiKey,
|
||||
("modified: " + tf.updated.getTime())
|
||||
});
|
||||
|
||||
uploadTask.execute();
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
getTask.execute();
|
||||
|
||||
|
||||
} else {
|
||||
// Upload the file
|
||||
HttpPutFile uploadTask = new HttpPutFile(serverURL + "/api/" + tf.filename, new File(baseDir + tf.filename), error -> {
|
||||
if (error != null)
|
||||
AlertManager.error(error);
|
||||
runningRequest.set(true);
|
||||
}
|
||||
}, new String[]{
|
||||
"api_key: " + apiKey,
|
||||
("modified: " + tf.updated.getTime())
|
||||
}); // Pass auth token if needed
|
||||
}, new String[]{
|
||||
"api_key: " + apiKey,
|
||||
("modified: " + tf.updated.getTime())
|
||||
}); // Pass auth token if needed
|
||||
|
||||
uploadTask.execute();
|
||||
await();
|
||||
uploadTask.execute();
|
||||
await();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setLocalFileTimestamp(File file, Date date) {
|
||||
file.setLastModified(date.getTime());
|
||||
}
|
||||
|
||||
// Download a file from the remote server
|
||||
void downloadFile(TransferFile tf, String serverURL) {
|
||||
runningRequest.set(false);
|
||||
File f = new File(baseDir + tf.filename);
|
||||
HttpGetFile uploadTask = new HttpGetFile(serverURL + "/api/" + tf.filename, f, new HttpGetFile.DownloadCallback() {
|
||||
@Override
|
||||
public void onResult(String error) {
|
||||
if(error != null)
|
||||
AlertManager.error(error);
|
||||
else
|
||||
setLocalFileTimestamp(f, tf.updated);
|
||||
runningRequest.set(true);
|
||||
|
||||
HttpGetFile uploadTask = new HttpGetFile(serverURL + "/api/" + tf.filename, f, (stream, error) -> {
|
||||
if(error != null) {
|
||||
AlertManager.error(error);
|
||||
return;
|
||||
} else if (stream == null) {
|
||||
AlertManager.error("Output stream from download was null!");
|
||||
return;
|
||||
}
|
||||
}); // Pass auth token if needed
|
||||
|
||||
byte[] bytes = stream.toByteArray();
|
||||
|
||||
if(FileEditor.requiresSpecialInteraction(tf.filename)) {
|
||||
FileEditor.syncColabArray(
|
||||
tf.filename,
|
||||
FileEditor.readFile(tf.filename),
|
||||
bytes
|
||||
);
|
||||
} else {
|
||||
FileEditor.writeFile(tf.filename, bytes);
|
||||
}
|
||||
|
||||
setLocalFileTimestamp(f, tf.updated);
|
||||
|
||||
runningRequest.set(true);
|
||||
|
||||
});
|
||||
|
||||
uploadTask.execute();
|
||||
await();
|
||||
|
||||
@@ -8,7 +8,11 @@ import static com.ridgebotics.ridgescout.utility.FileEditor.TBAAddress;
|
||||
import static com.ridgebotics.ridgescout.utility.FileEditor.TBAHeader;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Bundle;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -34,6 +38,7 @@ import com.ridgebotics.ridgescout.utility.JSONUtil;
|
||||
import com.ridgebotics.ridgescout.utility.RequestTask;
|
||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -41,6 +46,7 @@ import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
// Class to download data from a specific event and encode it.
|
||||
public class TBAEventFragment extends Fragment {
|
||||
@@ -71,23 +77,14 @@ public class TBAEventFragment extends Fragment {
|
||||
|
||||
Table = binding.matchTable;
|
||||
|
||||
Table.setStretchAllColumns(true);
|
||||
|
||||
AlertManager.startLoading("Loading Teams and Matches...");
|
||||
Table.removeAllViews();
|
||||
|
||||
// Table.removeAllViews();
|
||||
Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
TableRow tr1 = new TableRow(getContext());
|
||||
addTableText(tr1, "Downloading Teams...");
|
||||
Table.addView(tr1);
|
||||
|
||||
final RequestTask rq = new RequestTask();
|
||||
rq.onResult(teamsStr -> {
|
||||
TableRow tr11 = new TableRow(getContext());
|
||||
addTableText(tr11, "Downloading Matches...");
|
||||
Table.addView(tr11);
|
||||
|
||||
final RequestTask rq1 = new RequestTask();
|
||||
rq1.onResult(matchesStr -> {
|
||||
matchTable(matchesStr, teamsStr, eventData);
|
||||
@@ -103,18 +100,13 @@ public class TBAEventFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void addTableText(TableRow tr, String textStr){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
text.setText(textStr);
|
||||
tr.addView(text);
|
||||
tr.addView(new TextViewBuilder(getContext(), textStr)
|
||||
.size(18)
|
||||
// .align_center()
|
||||
.build());
|
||||
}
|
||||
|
||||
public void matchTable(String matchesString, String teamsString, JSONObject eventData){
|
||||
Table.removeAllViews();
|
||||
Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
try {
|
||||
final JSONArray matchData = new JSONArray(matchesString);
|
||||
// final JSONArray matchData = new JSONArray();
|
||||
@@ -129,27 +121,16 @@ public class TBAEventFragment extends Fragment {
|
||||
}
|
||||
|
||||
// Event code at top
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setText(matchKey);
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
Table.addView(new TextViewBuilder(getContext(), matchKey)
|
||||
.align_center()
|
||||
.size(18)
|
||||
.build());
|
||||
|
||||
// Event Name
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(matchName);
|
||||
tv.setTextSize(28);
|
||||
Table.addView(tv);
|
||||
|
||||
|
||||
Table.addView(new TextViewBuilder(getContext(), matchName)
|
||||
.align_center()
|
||||
.size(28)
|
||||
.build());
|
||||
|
||||
// Save button
|
||||
MaterialButton btn = new MaterialButton(getContext());
|
||||
@@ -164,68 +145,42 @@ public class TBAEventFragment extends Fragment {
|
||||
|
||||
|
||||
|
||||
// If there are no matches, add the error.
|
||||
// If there are no teams, don't allow the user to save the event and set the button to be invisible
|
||||
if(teamData.length() == 0){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("This event has no teams released yet...");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("This event has no teams released yet...");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
Table.addView(new TextViewBuilder(getContext(), "This event has no teams released yet...")
|
||||
.align_center()
|
||||
.size(18)
|
||||
.build());
|
||||
|
||||
btn.setVisibility(View.GONE);
|
||||
return;
|
||||
}else if(matchData.length() == 0){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("This event has no matches released yet...");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
Table.addView(new TextViewBuilder(getContext(), "This event has no matches released yet...")
|
||||
.align_center()
|
||||
.size(18)
|
||||
.build());
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Try manually adding practice matches.");
|
||||
tv.setTextSize(18);
|
||||
Table.addView(tv);
|
||||
Table.addView(new TextViewBuilder(getContext(), "Try manually adding practice matches.")
|
||||
.align_center()
|
||||
.size(18)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Teams");
|
||||
tv.setTextSize(28);
|
||||
Table.addView(tv);
|
||||
|
||||
Table.addView(
|
||||
new TextViewBuilder(getContext(), "Teams")
|
||||
.align_center()
|
||||
.size(28)
|
||||
.build()
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Sort the teams into numerical order
|
||||
int[] teams = new int[teamData.length()];
|
||||
|
||||
for(int i = 0 ; i < teamData.length(); i++){
|
||||
@@ -234,28 +189,26 @@ public class TBAEventFragment extends Fragment {
|
||||
|
||||
Arrays.sort(teams);
|
||||
|
||||
|
||||
// Loop through each match
|
||||
TableRow tr = null;
|
||||
for(int i=0; i < teamData.length(); i++){
|
||||
// frcTeam team = event.teams.get(i);
|
||||
int num = teams[i];
|
||||
|
||||
// If this is every 7th row, add the new row.
|
||||
if(i % 7 == 0){
|
||||
if(i != 0)
|
||||
Table.addView(tr);
|
||||
tr = new TableRow(getContext());
|
||||
}
|
||||
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
|
||||
text.setText(String.valueOf(num));
|
||||
// if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){
|
||||
// text.setBackgroundColor(0x3000FF00);
|
||||
// }else{
|
||||
// text.setBackgroundColor(0x30FF0000);
|
||||
// }
|
||||
tr.addView(text);
|
||||
tr.addView(
|
||||
new TextViewBuilder(getContext(), String.valueOf(num))
|
||||
.align_center()
|
||||
.size(18)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
if(tr != null)
|
||||
Table.addView(tr);
|
||||
@@ -268,19 +221,13 @@ public class TBAEventFragment extends Fragment {
|
||||
|
||||
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Matches");
|
||||
tv.setTextSize(28);
|
||||
Table.addView(tv);
|
||||
|
||||
|
||||
|
||||
|
||||
Table.addView(
|
||||
new TextViewBuilder(getContext(), "Matches")
|
||||
.align_center()
|
||||
.size(28)
|
||||
.build()
|
||||
);
|
||||
|
||||
tr = new TableRow(getContext());
|
||||
addTableText(tr, "#");
|
||||
addTableText(tr, "Red-1");
|
||||
@@ -334,22 +281,24 @@ public class TBAEventFragment extends Fragment {
|
||||
int[] redKeys = new int[3];
|
||||
|
||||
for(int b=0;b<6;b++){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
tr.addView(text);
|
||||
TextViewBuilder text = new TextViewBuilder(getContext())
|
||||
.size(18)
|
||||
.align_center();
|
||||
|
||||
if(b < 3){
|
||||
String str = redAlliance.getString(b).substring(3);
|
||||
redKeys[b] = Integer.parseInt(str);
|
||||
text.setText(str);
|
||||
text.setBackgroundColor(tba_red);
|
||||
text.text(str);
|
||||
text.tv.setBackgroundColor(tba_red);
|
||||
}else{
|
||||
String str = blueAlliance.getString(b-3).substring(3);
|
||||
blueKeys[b-3] = Integer.parseInt(str);
|
||||
text.setText(str);
|
||||
text.setBackgroundColor(tba_blue);
|
||||
text.text(str);
|
||||
text.tv.setBackgroundColor(tba_blue);
|
||||
}
|
||||
|
||||
|
||||
tr.addView(text.build());
|
||||
}
|
||||
|
||||
Table.addView(tr);
|
||||
@@ -364,14 +313,6 @@ public class TBAEventFragment extends Fragment {
|
||||
toggle = !toggle;
|
||||
}
|
||||
|
||||
// btn.setOnClickListener(v -> {
|
||||
// if(saveData(matchesOBJ, teamData, eventData)){
|
||||
// alert("Info", "Saved!");
|
||||
// }else{
|
||||
// alert("Error", "Error saving files.");
|
||||
// }
|
||||
// });
|
||||
|
||||
}catch (JSONException j){
|
||||
AlertManager.error("Failed Downloading", j);
|
||||
AlertManager.stopLoading();
|
||||
@@ -379,7 +320,7 @@ public class TBAEventFragment extends Fragment {
|
||||
}
|
||||
|
||||
private boolean saveData(ArrayList<frcMatch> matchData, JSONArray teamData, JSONObject eventData){
|
||||
AlertManager.startLoading("Saving data...");
|
||||
AlertManager.startLoading("Downloading team data...");
|
||||
|
||||
Thread t = new Thread(() -> {
|
||||
try {
|
||||
@@ -404,16 +345,44 @@ public class TBAEventFragment extends Fragment {
|
||||
teamObj.country = team.getString("country");
|
||||
teamObj.startingYear = team.getInt("rookie_year");
|
||||
|
||||
ImageRequestTask imageRequestTask = new ImageRequestTask();
|
||||
|
||||
imageRequestTask.onResult(bitmap -> {
|
||||
teamObj.bitmap = bitmap;
|
||||
teamObj.teamColor = frcTeam.findPrimaryColor(bitmap);
|
||||
teams.add(teamObj);
|
||||
RequestTask rq = new RequestTask();
|
||||
rq.onResult(s -> {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(s);
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(0);
|
||||
String base64 = jsonObject.getJSONObject("details").getString("base64Image");
|
||||
|
||||
byte[] decodedData = Base64.decode(base64, Base64.DEFAULT);
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(decodedData, 0, decodedData.length);
|
||||
|
||||
// System.out.println(base64);
|
||||
|
||||
teamObj.bitmap = bitmap;
|
||||
teamObj.teamColor = frcTeam.findPrimaryColor(bitmap);
|
||||
|
||||
Log.i("TBA", "Got icon for team " + teamObj.teamNumber);
|
||||
|
||||
|
||||
} catch (Exception e){
|
||||
Log.i("TBA", "Failed to icon for team " + teamObj.teamNumber);
|
||||
} finally {
|
||||
teams.add(teamObj);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
imageRequestTask.execute("https://www.thebluealliance.com/avatar/" + year + "/frc" + teamObj.teamNumber + ".png");
|
||||
rq.execute((TBAAddress + "team/frc" + teamObj.teamNumber + "/media/" + year), TBAHeader);
|
||||
|
||||
// ImageRequestTask imageRequestTask = new ImageRequestTask();
|
||||
//
|
||||
// imageRequestTask.onResult(bitmap -> {
|
||||
// teamObj.bitmap = bitmap;
|
||||
// teamObj.teamColor = frcTeam.findPrimaryColor(bitmap);
|
||||
// teams.add(teamObj);
|
||||
//
|
||||
// return null;
|
||||
// });
|
||||
// imageRequestTask.execute("https://www.thebluealliance.com/avatar/" + year + "/frc" + teamObj.teamNumber + ".png");
|
||||
}
|
||||
|
||||
while (teams.size() != teamData.length()) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.ridgebotics.ridgescout.ui.views.TBAEventOption;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.RequestTask;
|
||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -54,12 +55,6 @@ public class TBASelectorFragment extends Fragment {
|
||||
|
||||
Table = binding.matchTable;
|
||||
|
||||
Table.setStretchAllColumns(true);
|
||||
|
||||
TableRow tr = new TableRow(getContext());
|
||||
addTableText(tr, "Loading Events...");
|
||||
Table.addView(tr);
|
||||
|
||||
startLoading("Loading Events...");
|
||||
|
||||
final RequestTask rq = new RequestTask();
|
||||
@@ -77,14 +72,6 @@ public class TBASelectorFragment extends Fragment {
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void addTableText(TableRow tr, String textStr){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
||||
text.setText(textStr);
|
||||
tr.addView(text);
|
||||
}
|
||||
|
||||
public static int getEventTypeWeight(String type){
|
||||
switch(type){
|
||||
case "Preseason": return -3;
|
||||
@@ -103,7 +90,7 @@ public class TBASelectorFragment extends Fragment {
|
||||
public void eventTable(String dataString){
|
||||
|
||||
Table.removeAllViews();
|
||||
Table.setStretchAllColumns(true);
|
||||
// Table.setStretchAllColumns(true);
|
||||
Table.bringToFront();
|
||||
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
@@ -178,12 +165,12 @@ public class TBASelectorFragment extends Fragment {
|
||||
try {
|
||||
Date startDate = format.parse(j.getString("start_date"));
|
||||
Date endDate = format.parse(j.getString("end_date"));
|
||||
if(currentTime.after(endDate)){
|
||||
if(currentTime.after(startDate) && currentTime.before(endDate)) {
|
||||
row.setColor(tba_current);
|
||||
} else if(currentTime.after(endDate)){
|
||||
row.setColor(tba_previous);
|
||||
}else if(currentTime.before(startDate)){
|
||||
row.setColor(tba_next);
|
||||
}else if(currentTime.after(startDate) && currentTime.before(endDate)){
|
||||
row.setColor(tba_current);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlertManager.error("Failed finding start and end dates!", e);
|
||||
|
||||
@@ -81,6 +81,12 @@ public class FieldPosView extends FrameLayout {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.ridgebotics.ridgescout.ui.views;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerHolder<T>> {
|
||||
private List<T> items;
|
||||
private final int layoutResId;
|
||||
private final RecyclerHolderFactory<T> viewHolderFactory;
|
||||
private RecyclerClickListener<T> onItemClickListener;
|
||||
|
||||
public RecyclerAdapter(int layoutResId, RecyclerHolderFactory<T> viewHolderFactory) {
|
||||
this.items = new ArrayList<>();
|
||||
this.layoutResId = layoutResId;
|
||||
this.viewHolderFactory = viewHolderFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(layoutResId, parent, false);
|
||||
return viewHolderFactory.createViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerHolder<T> holder, int position) {
|
||||
T item = items.get(position);
|
||||
holder.bind(item, position);
|
||||
holder.setOnItemClickListener(item, onItemClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
// List management methods
|
||||
public void setItems(List<T> newItems) {
|
||||
this.items.clear();
|
||||
if (newItems != null) {
|
||||
this.items.addAll(newItems);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addItem(T item) {
|
||||
items.add(item);
|
||||
notifyItemInserted(items.size() - 1);
|
||||
}
|
||||
|
||||
public void addItem(int position, T item) {
|
||||
items.add(position, item);
|
||||
notifyItemInserted(position);
|
||||
}
|
||||
|
||||
public void removeItem(int position) {
|
||||
if (position >= 0 && position < items.size()) {
|
||||
items.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(T item) {
|
||||
int position = items.indexOf(item);
|
||||
if (position != -1) {
|
||||
removeItem(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateItem(int position, T item) {
|
||||
if (position >= 0 && position < items.size()) {
|
||||
items.set(position, item);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
int size = items.size();
|
||||
items.clear();
|
||||
notifyItemRangeRemoved(0, size);
|
||||
}
|
||||
|
||||
public T getItem(int position) {
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
public List<T> getItems() {
|
||||
return new ArrayList<>(items);
|
||||
}
|
||||
|
||||
public void setOnItemClickListener(RecyclerClickListener<T> listener) {
|
||||
this.onItemClickListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.ridgebotics.ridgescout.ui.views;
|
||||
|
||||
public interface RecyclerClickListener<T> {
|
||||
void onItemClick(T item, int position);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.ridgebotics.ridgescout.ui.views;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public abstract class RecyclerHolder<T> extends RecyclerView.ViewHolder {
|
||||
public RecyclerHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public abstract void bind(T item, int position);
|
||||
|
||||
// Optional method for handling item clicks
|
||||
public void setOnItemClickListener(T item, RecyclerClickListener<T> listener) {
|
||||
if (listener != null) {
|
||||
itemView.setOnClickListener(v -> listener.onItemClick(item, getAdapterPosition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.ridgebotics.ridgescout.ui.views;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface RecyclerHolderFactory<T> {
|
||||
RecyclerHolder<T> createViewHolder(View itemView);
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package com.ridgebotics.ridgescout.ui.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import java.util.List;
|
||||
|
||||
public class RecyclerList<T> extends RecyclerView {
|
||||
private RecyclerAdapter<T> adapter;
|
||||
|
||||
public RecyclerList(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public RecyclerList(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public RecyclerList(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// Set default layout manager
|
||||
setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
// Enable optimizations
|
||||
setHasFixedSize(true);
|
||||
setItemViewCacheSize(20);
|
||||
setDrawingCacheEnabled(true);
|
||||
setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
|
||||
}
|
||||
|
||||
// Setup method to configure the RecyclerView
|
||||
public RecyclerList<T> setup(int layoutResId, RecyclerHolderFactory<T> RecyclerHolderFactory) {
|
||||
adapter = new RecyclerAdapter<>(layoutResId, RecyclerHolderFactory);
|
||||
setAdapter(adapter);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Layout manager convenience methods
|
||||
public RecyclerList<T> withLinearLayout() {
|
||||
setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public RecyclerList<T> withLinearLayout(int orientation) {
|
||||
setLayoutManager(new LinearLayoutManager(getContext(), orientation, false));
|
||||
return this;
|
||||
}
|
||||
|
||||
public RecyclerList<T> withGridLayout(int spanCount) {
|
||||
setLayoutManager(new GridLayoutManager(getContext(), spanCount));
|
||||
return this;
|
||||
}
|
||||
|
||||
public RecyclerList<T> withDivider() {
|
||||
DividerItemDecoration divider = new DividerItemDecoration(getContext(),
|
||||
DividerItemDecoration.VERTICAL);
|
||||
addItemDecoration(divider);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RecyclerList<T> withItemClickListener(RecyclerClickListener<T> listener) {
|
||||
if (adapter != null) {
|
||||
adapter.setOnItemClickListener(listener);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Data management methods
|
||||
public void setItems(List<T> items) {
|
||||
if (adapter != null) {
|
||||
adapter.setItems(items);
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(T item) {
|
||||
if (adapter != null) {
|
||||
adapter.addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(int position, T item) {
|
||||
if (adapter != null) {
|
||||
adapter.addItem(position, item);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(int position) {
|
||||
if (adapter != null) {
|
||||
adapter.removeItem(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(T item) {
|
||||
if (adapter != null) {
|
||||
adapter.removeItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateItem(int position, T item) {
|
||||
if (adapter != null) {
|
||||
adapter.updateItem(position, item);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (adapter != null) {
|
||||
adapter.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public T getItem(int position) {
|
||||
return adapter != null ? adapter.getItem(position) : null;
|
||||
}
|
||||
|
||||
public List<T> getItems() {
|
||||
return adapter != null ? adapter.getItems() : null;
|
||||
}
|
||||
|
||||
public RecyclerAdapter<T> getGenericAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
}
|
||||
@@ -19,37 +19,34 @@ import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
|
||||
// A view that acts as a row specifically to display a team and their icon in a list formmt.
|
||||
public class TeamListOption extends RecyclerHolder<frcTeam> {
|
||||
public class TeamListOption extends LinearLayout {
|
||||
public TeamListOption(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public TeamListOption(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
// public TeamListOption(Context context, @Nullable AttributeSet attrs) {
|
||||
// super(context, attrs);
|
||||
// init(context);
|
||||
// }
|
||||
//
|
||||
// public TeamListOption(Context context) {
|
||||
// super(context);
|
||||
// init(context);
|
||||
// }
|
||||
//
|
||||
private TextView teamNumber;
|
||||
private TextView teamName;
|
||||
|
||||
private ImageView teamLogo;
|
||||
private ConstraintLayout box;
|
||||
private View coloredBackground;
|
||||
//
|
||||
public TeamListOption(View view) {
|
||||
super(view);
|
||||
// LayoutInflater.from(context).inflate(R.layout.view_team_option, this, true);
|
||||
|
||||
teamNumber = view.findViewById(R.id.field_option_type);
|
||||
teamName = view.findViewById(R.id.field_option_name);
|
||||
teamLogo = view.findViewById(R.id.team_option_logo);
|
||||
public void init(Context context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.view_team_option, this, true);
|
||||
|
||||
teamNumber = findViewById(R.id.field_option_type);
|
||||
teamName = findViewById(R.id.field_option_name);
|
||||
teamLogo = findViewById(R.id.team_option_logo);
|
||||
|
||||
|
||||
box = view.findViewById(R.id.team_option_box);
|
||||
coloredBackground = view.findViewById(R.id.team_option_background);
|
||||
box = findViewById(R.id.team_option_box);
|
||||
coloredBackground = findViewById(R.id.team_option_background);
|
||||
}
|
||||
|
||||
public void setTeamNumber(int num){
|
||||
@@ -62,7 +59,6 @@ public class TeamListOption extends RecyclerHolder<frcTeam> {
|
||||
|
||||
public void setTeamLogo(Bitmap bitmap){
|
||||
teamLogo.setImageBitmap(bitmap);
|
||||
showLogo();
|
||||
}
|
||||
|
||||
public void hideLogo(){
|
||||
@@ -72,8 +68,7 @@ public class TeamListOption extends RecyclerHolder<frcTeam> {
|
||||
teamLogo.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(frcTeam team, int position){
|
||||
public void fromTeam(frcTeam team){
|
||||
setTeamNumber(team.teamNumber);
|
||||
setTeamName(team.teamName);
|
||||
|
||||
|
||||
@@ -67,9 +67,9 @@ public class Colors {
|
||||
public static final int fileselector_unselected_color = 0x50006600;
|
||||
|
||||
// TBA
|
||||
public static final int tba_previous = 0x30FF0000;
|
||||
public static final int tba_current = 0x50ff0000;
|
||||
public static final int tba_next = 0x30FFFF00;
|
||||
public static final int tba_previous = Color.argb(30, 64,64,64);
|
||||
public static final int tba_current = 0x7f00ff00;
|
||||
public static final int tba_next = Color.argb(30, 192,192,192);
|
||||
public static final int tba_red = 0x50ff0000;
|
||||
public static final int tba_blue = 0x500000ff;
|
||||
public static final int tba_toggle_background = 0x30000000;
|
||||
|
||||
@@ -2,13 +2,10 @@ package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import com.ridgebotics.ridgescout.scoutingData.Fields;
|
||||
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
||||
import com.ridgebotics.ridgescout.types.ColabArray;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.input.FieldType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
// Static class to hold loaded data, for ease of access.
|
||||
public class DataManager {
|
||||
public static String evcode;
|
||||
@@ -62,37 +59,39 @@ public class DataManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> rescout_list = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
|
||||
public static ColabArray rescout_list = new ColabArray();
|
||||
public static void reload_rescout_list(){
|
||||
if(!FileEditor.fileExist(evcode + ".rescout")) {rescout_list = new ArrayList<>(); return;}
|
||||
byte[] file = FileEditor.readFile(evcode + ".rescout");
|
||||
if(file == null) {rescout_list = new ArrayList<>(); return;}
|
||||
String filename = evcode + ".rescout";
|
||||
if(!FileEditor.fileExist(filename)) {rescout_list = new ColabArray(); return;}
|
||||
byte[] file = FileEditor.readFile(filename);
|
||||
if(file == null) {rescout_list = new ColabArray(); return;}
|
||||
|
||||
try {
|
||||
BuiltByteParser bbp = new BuiltByteParser(file);
|
||||
rescout_list = new ArrayList<>(Arrays.asList((String[]) (bbp.parse().get(0).get())));
|
||||
|
||||
rescout_list = ColabArray.decode(file);
|
||||
} catch (Exception e){
|
||||
AlertManager.error("Error loading scout fields", e);
|
||||
rescout_list = new ArrayList<>();
|
||||
AlertManager.error("Error loading rescouting list", e);
|
||||
rescout_list = new ColabArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static void save_rescout_list() {
|
||||
String filename = evcode + ".rescout";
|
||||
try {
|
||||
if(rescout_list.size() == 0){
|
||||
FileEditor.deleteFile(evcode + ".rescout");
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuilder bb = new ByteBuilder();
|
||||
bb.addStringArray(rescout_list.toArray(new String[0]));
|
||||
FileEditor.writeFile(evcode + ".rescout", bb.build());
|
||||
FileEditor.writeFile(filename, rescout_list.encode());
|
||||
} catch (Exception e){
|
||||
AlertManager.error("Error saving scout fields", e);
|
||||
AlertManager.error("Error saving rescouting list", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static String scoutNotice = "";
|
||||
|
||||
public static void reload_scout_notice(){
|
||||
@@ -106,7 +105,7 @@ public class DataManager {
|
||||
|
||||
} catch (Exception e){
|
||||
AlertManager.error("Error loading scout notice", e);
|
||||
rescout_list = new ArrayList<>();
|
||||
scoutNotice = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_transferValues;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_transferValues;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
import com.ridgebotics.ridgescout.types.ColabArray;
|
||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||
|
||||
@@ -15,6 +23,8 @@ import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -27,18 +37,17 @@ import java.util.zip.Inflater;
|
||||
|
||||
// Helper class for binary editing
|
||||
public final class FileEditor {
|
||||
@SuppressLint("SdCardPath")
|
||||
public final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
||||
public static final byte internalDataVersion = 0x01;
|
||||
public static final int maxCompressedBlockSize = 4096;
|
||||
public static final int lengthHeaderBytes = 3;
|
||||
|
||||
|
||||
public static final String TBAAddress = "https://www.thebluealliance.com/api/v3/";
|
||||
|
||||
// Hardcoded API key go brrr
|
||||
public static final String TBAHeader = "X-TBA-Auth-Key: tjEKSZojAU2pgbs2mBt06SKyOakVhLutj3NwuxLTxPKQPLih11aCIwRIVFXKzY4e";
|
||||
|
||||
// private TimeZone localTimeZone = TimeZone.getDefault();
|
||||
|
||||
|
||||
|
||||
public static String binaryVisualize(byte[] bytes){
|
||||
String returnStr = "";
|
||||
@@ -233,16 +242,19 @@ public final class FileEditor {
|
||||
// }
|
||||
|
||||
|
||||
|
||||
public static boolean writeFile(String filepath, byte[] data) {
|
||||
return writeFile(new File(baseDir + filepath), data);
|
||||
}
|
||||
|
||||
public static boolean writeFile(File file, byte[] data) {
|
||||
try {
|
||||
FileOutputStream output = new FileOutputStream(baseDir + filepath);
|
||||
FileOutputStream output = new FileOutputStream(file.getPath());
|
||||
output.write(data);
|
||||
output.close();
|
||||
|
||||
// Date d = new Date();
|
||||
|
||||
new File(baseDir + filepath).setLastModified(new Date().getTime());
|
||||
file.setLastModified(new Date().getTime());
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -251,6 +263,11 @@ 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){
|
||||
if(fileExist(filepath)){
|
||||
return true;
|
||||
@@ -279,10 +296,15 @@ public final class FileEditor {
|
||||
}
|
||||
|
||||
public static byte[] readFile(String path){
|
||||
return readFileExact(baseDir + path);
|
||||
return readFileExact(new File(baseDir + path));
|
||||
}
|
||||
public static byte[] readFileExact(String path){
|
||||
File file = new File(path);
|
||||
|
||||
public static byte[] readFile(File path){
|
||||
return readFileExact(path);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] readFileExact(File file){
|
||||
int size = (int) file.length();
|
||||
byte[] bytes = new byte[size];
|
||||
try {
|
||||
@@ -290,9 +312,6 @@ public final class FileEditor {
|
||||
buf.read(bytes, 0, bytes.length);
|
||||
buf.close();
|
||||
return bytes;
|
||||
} catch (FileNotFoundException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
return null;
|
||||
@@ -314,6 +333,29 @@ public final class FileEditor {
|
||||
|
||||
|
||||
|
||||
public static String getSHA256Hash(String filePath) throws IOException, NoSuchAlgorithmException {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
FileInputStream fis = new FileInputStream(baseDir + filePath);
|
||||
byte[] byteArray = new byte[1024];
|
||||
int bytesCount = 0;
|
||||
|
||||
while ((bytesCount = fis.read(byteArray)) != -1) {
|
||||
digest.update(byteArray, 0, bytesCount);
|
||||
}
|
||||
fis.close();
|
||||
|
||||
byte[] bytes = digest.digest();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean setEvent(frcEvent event){
|
||||
@@ -373,25 +415,21 @@ public final class FileEditor {
|
||||
|
||||
|
||||
|
||||
|
||||
public static String[] getEventFiles(String evcode){
|
||||
public static String[] getFiles(){
|
||||
File f = new File(baseDir);
|
||||
File[] files = f.listFiles();
|
||||
|
||||
if(files == null){return new String[0];}
|
||||
|
||||
ArrayList<String> outFiles = new ArrayList<>();
|
||||
outFiles.add("matches.fields");
|
||||
outFiles.add("pits.fields");
|
||||
// outFiles.add(evcode + ".eventdata");
|
||||
List<String> outFiles = new ArrayList<>();
|
||||
|
||||
for (File file : files) {
|
||||
String name = file.getName();
|
||||
if(!file.isDirectory() && name.startsWith(evcode)) {
|
||||
if (!file.isDirectory()) {
|
||||
outFiles.add(file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String[] filenames = outFiles.toArray(new String[0]);
|
||||
|
||||
try {
|
||||
@@ -413,6 +451,24 @@ public final class FileEditor {
|
||||
return filenames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String[] getEventFiles(String evcode){
|
||||
String[] files = getFiles();
|
||||
|
||||
List<String> outFiles = new ArrayList<>();
|
||||
outFiles.add("matches.fields");
|
||||
outFiles.add("pits.fields");
|
||||
|
||||
for (String file : files) {
|
||||
if(file.startsWith(evcode)) {
|
||||
outFiles.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
return outFiles.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/7620401/how-to-convert-image-file-data-in-a-byte-array-to-a-bitmap
|
||||
// public static String imageToBitMap(byte[] data) throws IOException {
|
||||
// Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
||||
@@ -425,5 +481,72 @@ public final class FileEditor {
|
||||
public static boolean setTeams(Context context, String key, ArrayList<frcTeam> teams){
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<String> findCorruptedFiles() {
|
||||
List<String> removeFiles = new ArrayList<>();
|
||||
String[] localFiles = FileEditor.getFiles();
|
||||
|
||||
DataManager.reload_match_fields();
|
||||
DataManager.reload_pit_fields();
|
||||
|
||||
for(int i = 0; i < localFiles.length; i++){
|
||||
String filename = localFiles[i];
|
||||
|
||||
String[] split = filename.split("\\.");
|
||||
|
||||
String extention =split[split.length-1];
|
||||
|
||||
|
||||
try {
|
||||
switch (extention) {
|
||||
case "matchscoutdata":
|
||||
ScoutingDataWriter.load(filename, match_values, match_transferValues);
|
||||
break;
|
||||
case "pitscoutdata":
|
||||
ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
removeFiles.add(filename);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return removeFiles;
|
||||
}
|
||||
|
||||
public static boolean requiresSpecialInteraction(String name) {
|
||||
// String name = file.getName();
|
||||
|
||||
if(!fileExist(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(name.endsWith(".rescout")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void syncColabArray(String filename, byte[] currentBytes, byte[] newBytes) {
|
||||
if(!fileExist(filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
if(filename.endsWith(".rescout")) {
|
||||
ColabArray colabArrayCurrent = ColabArray.decode(currentBytes);
|
||||
ColabArray colabArrayNew = ColabArray.decode(newBytes);
|
||||
|
||||
colabArrayCurrent.append(colabArrayNew);
|
||||
writeFile(filename, colabArrayCurrent.encode());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlertManager.error("Failed to sync ColabArray!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,16 @@ import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
// Class to download remote file.
|
||||
public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
|
||||
public interface DownloadCallback {
|
||||
void onResult(String error);
|
||||
void onResult(ByteArrayOutputStream bytes, String error);
|
||||
}
|
||||
|
||||
private String downloadUrl;
|
||||
private File destinationFile;
|
||||
private ByteArrayOutputStream outputStream;
|
||||
private DownloadCallback callback;
|
||||
private String errorMessage;
|
||||
public HttpGetFile(String downloadUrl, File destinationFile, DownloadCallback callback) {
|
||||
@@ -23,9 +25,12 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
|
||||
@Override
|
||||
protected File doInBackground(Void... voids) {
|
||||
return run();
|
||||
}
|
||||
|
||||
public File run() {
|
||||
HttpURLConnection connection = null;
|
||||
InputStream inputStream = null;
|
||||
FileOutputStream outputStream = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(downloadUrl);
|
||||
@@ -64,7 +69,7 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
}
|
||||
}
|
||||
|
||||
outputStream = new FileOutputStream(destinationFile);
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
long downloadedBytes = 0;
|
||||
@@ -87,6 +92,8 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
}
|
||||
|
||||
outputStream.flush();
|
||||
|
||||
// FileEditor.writeFile(destinationFile, outputStream.toByteArray());
|
||||
// Log.d(TAG, "Download successful. File saved to: " + destinationFile.getAbsolutePath());
|
||||
return destinationFile;
|
||||
|
||||
@@ -104,7 +111,7 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
@Override
|
||||
protected void onPostExecute(File result) {
|
||||
if (callback != null) {
|
||||
callback.onResult(errorMessage);
|
||||
callback.onResult(outputStream, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +119,7 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
protected void onCancelled() {
|
||||
deletePartialFile();
|
||||
if (callback != null) {
|
||||
callback.onResult("Download cancelled");
|
||||
callback.onResult(null, "Download cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,8 +137,7 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
return response.toString();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
// Log.e(TAG, "Error reading error response", e);
|
||||
AlertManager.error("Error reading error response", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -139,9 +145,9 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
private void deletePartialFile() {
|
||||
if (destinationFile != null && destinationFile.exists()) {
|
||||
if (destinationFile.delete()) {
|
||||
// Log.d(TAG, "Partial download file deleted");
|
||||
AlertManager.error("Partial download file deleted");
|
||||
} else {
|
||||
// Log.w(TAG, "Failed to delete partial download file");
|
||||
AlertManager.error("Failed to delete partial download file");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,15 +156,13 @@ public class HttpGetFile extends AsyncTask<Void, Integer, File> {
|
||||
try {
|
||||
if (inputStream != null) inputStream.close();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
// Log.e(TAG, "Error closing input stream", e);
|
||||
AlertManager.error("Error closing input stream", e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (outputStream != null) outputStream.close();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
// Log.e(TAG, "Error closing output stream", e);
|
||||
AlertManager.error("Error closing output stream", e);
|
||||
}
|
||||
|
||||
if (connection != null) {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.AsyncTask;
|
||||
//import android.util.Log;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
// Class to send HTTP PUT request to upload file
|
||||
public class HttpPutFile extends AsyncTask<Void, Integer, Boolean> {
|
||||
|
||||
// private static final String TAG = "FileUploadTask";
|
||||
@@ -27,8 +30,13 @@ public class HttpPutFile extends AsyncTask<Void, Integer, Boolean> {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
@SuppressLint("WrongThread")
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
return run();
|
||||
}
|
||||
|
||||
public boolean run() {
|
||||
HttpURLConnection connection = null;
|
||||
InputStream fileInputStream = null;
|
||||
OutputStream outputStream = null;
|
||||
@@ -49,8 +57,8 @@ public class HttpPutFile extends AsyncTask<Void, Integer, Boolean> {
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestProperty("Content-Type", "application/octet-stream");
|
||||
connection.setRequestProperty("Content-Length", String.valueOf(fileToUpload.length()));
|
||||
connection.setConnectTimeout(30000); // 30 seconds
|
||||
connection.setReadTimeout(60000); // 60 seconds
|
||||
connection.setConnectTimeout(5000); // 5 seconds
|
||||
connection.setReadTimeout(10000); // 10 seconds
|
||||
|
||||
for(int i = 0; i < headers.length; i++){
|
||||
String[] split = headers[i].split(": ");
|
||||
@@ -95,8 +103,8 @@ public class HttpPutFile extends AsyncTask<Void, Integer, Boolean> {
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AlertManager.error(e);
|
||||
errorMessage = "Upload error: " + e.getMessage();
|
||||
AlertManager.error(errorMessage, e);
|
||||
// Log.e(TAG, errorMessage, e);
|
||||
return false;
|
||||
} finally {
|
||||
@@ -133,25 +141,23 @@ public class HttpPutFile extends AsyncTask<Void, Integer, Boolean> {
|
||||
return response.toString();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
// Log.e(TAG, "Error reading error response", e);
|
||||
AlertManager.error("Error reading error response", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Clean up stream
|
||||
private void closeResources(InputStream inputStream, OutputStream outputStream, HttpURLConnection connection) {
|
||||
try {
|
||||
if (inputStream != null) inputStream.close();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
// Log.e(TAG, "Error closing input stream", e);
|
||||
AlertManager.error("Error closing input stream", e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (outputStream != null) outputStream.close();
|
||||
} catch (IOException e) {
|
||||
AlertManager.error(e);
|
||||
// Log.e(TAG, "Error closing output stream", e);
|
||||
AlertManager.error("Error closing output stream", e);
|
||||
}
|
||||
|
||||
if (connection != null) {
|
||||
|
||||
@@ -46,8 +46,8 @@ public class SettingsManager {
|
||||
hm.put(UnameKey, "Username");
|
||||
hm.put(SelEVCodeKey, "unset");
|
||||
hm.put(WifiModeKey, false);
|
||||
hm.put(YearNumKey, 2025);
|
||||
hm.put(FieldImageKey, "2025");
|
||||
hm.put(YearNumKey, 2026);
|
||||
hm.put(FieldImageKey, "2026");
|
||||
hm.put(MatchNumKey, 0);
|
||||
hm.put(AllyPosKey, "red-1");
|
||||
hm.put(DataModeKey, 0);
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.ridgebotics.ridgescout.utility;
|
||||
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.ridgebotics.ridgescout.types.ColabArray;
|
||||
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ToDelete {
|
||||
public static final String filename = "todelete.colabarray";
|
||||
|
||||
public static void findCorruptedFiles(Context c) {
|
||||
new Thread(() -> {
|
||||
AlertManager.startLoading("Loading files...");
|
||||
List<String> filenames = FileEditor.findCorruptedFiles();
|
||||
AlertManager.stopLoading();
|
||||
((Activity) c).runOnUiThread(() -> {
|
||||
deleteFiles(c, filenames, true);
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void deleteFiles(Context c, List<String> files, boolean defaultOption) {
|
||||
ScrollView sv = new ScrollView(c);
|
||||
LinearLayout ll = new LinearLayout(c);
|
||||
ll.setOrientation(VERTICAL);
|
||||
sv.addView(ll);
|
||||
|
||||
CheckBox[] checkboxes = new CheckBox[files.size()];
|
||||
|
||||
for(int i =0; i < files.size(); i++){
|
||||
CheckBox cb = new CheckBox(c);
|
||||
cb.setText(files.get(i));
|
||||
cb.setChecked(defaultOption);
|
||||
ll.addView(cb);
|
||||
checkboxes[i] = cb;
|
||||
}
|
||||
|
||||
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(c);
|
||||
alert.setTitle("Delete files");
|
||||
alert.setView(sv);
|
||||
alert.setNeutralButton("Cancel", null);
|
||||
alert.setPositiveButton("Delete", (_dialogInterface, _i) -> {
|
||||
List<String> delete_files = new ArrayList<>();
|
||||
for(int i = 0; i < files.size(); i++) {
|
||||
if(checkboxes[i].isChecked())
|
||||
delete_files.add(files.get(i));
|
||||
}
|
||||
|
||||
|
||||
AlertDialog.Builder confirm = new AlertDialog.Builder(c);
|
||||
alert.setTitle("Confirm");
|
||||
alert.setView(new TextViewBuilder(c, "Are you sure you want to delete " + delete_files.size() + " files?").build());
|
||||
alert.setNeutralButton("Cancel", null);
|
||||
alert.setPositiveButton("Delete", (dialogInterface, i) -> {
|
||||
deleteFiles(delete_files);
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
alert.create().show();
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
alert.create().show();
|
||||
}
|
||||
|
||||
public static ColabArray todelete_list = new ColabArray();
|
||||
public static void reload_todelete_list(){
|
||||
if(!FileEditor.fileExist(ToDelete.filename)) {todelete_list = new ColabArray(); return;}
|
||||
byte[] file = FileEditor.readFile(ToDelete.filename);
|
||||
if(file == null) {todelete_list = new ColabArray(); return;}
|
||||
|
||||
try {
|
||||
todelete_list = ColabArray.decode(file);
|
||||
} catch (Exception e){
|
||||
AlertManager.error("Error loading todelete list", e);
|
||||
todelete_list = new ColabArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static void save_todelete_list() {
|
||||
try {
|
||||
FileEditor.writeFile(ToDelete.filename, todelete_list.encode());
|
||||
} catch (Exception e){
|
||||
AlertManager.error("Error saving todelete list", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteFiles(List<String> toDelete) {
|
||||
reload_todelete_list();
|
||||
|
||||
for(String file : toDelete) {
|
||||
|
||||
String hash;
|
||||
try {
|
||||
hash = FileEditor.getSHA256Hash(file);
|
||||
} catch (Exception e) {
|
||||
AlertManager.error("Failed to get hash of file: " + file, e);
|
||||
continue;
|
||||
}
|
||||
|
||||
todelete_list.add(file+","+hash);
|
||||
|
||||
FileEditor.deleteFile(file);
|
||||
}
|
||||
|
||||
save_todelete_list();
|
||||
}
|
||||
|
||||
public static void deleteFiles() {
|
||||
reload_todelete_list();
|
||||
List<String> toDelete = todelete_list.get();
|
||||
for(String filename : FileEditor.getFiles()){
|
||||
try {
|
||||
String hash = FileEditor.getSHA256Hash(filename);
|
||||
|
||||
if(toDelete.contains(filename+","+hash)) {
|
||||
FileEditor.deleteFile(filename);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AlertManager.error("Failed to get hash of file: " + filename, e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean contains(String localfile) {
|
||||
try {
|
||||
String hash = FileEditor.getSHA256Hash(localfile);
|
||||
return contains(localfile, hash);
|
||||
} catch (Exception e) {
|
||||
AlertManager.error("Failed to get hash of file: " + localfile, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean contains(String filename, String hash){
|
||||
return todelete_list.contains(filename+","+hash);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.ridgebotics.ridgescout.utility.builders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class TextViewBuilder {
|
||||
public TextView tv;
|
||||
public TextViewBuilder(Context c) {
|
||||
tv = new TextView(c);
|
||||
}
|
||||
|
||||
public TextViewBuilder(Context c, String str) {
|
||||
tv = new TextView(c);
|
||||
tv.setText(str);
|
||||
}
|
||||
|
||||
public TextViewBuilder size(float size) {
|
||||
tv.setTextSize(size);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder text(String str) {
|
||||
tv.setText(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder padding(int borders) {
|
||||
tv.setPadding(borders,borders,borders,borders);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder padding(int horisontal, int vertical) {
|
||||
tv.setPadding(horisontal,vertical,horisontal,vertical);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder padding(int left, int right, int top, int bottom) {
|
||||
tv.setPadding(left,top,right,bottom);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder align_left() {
|
||||
tv.setGravity(Gravity.START);
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder align_center() {
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
// FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
||||
// ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
// ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
// );
|
||||
// params.gravity = Gravity.CENTER;
|
||||
// tv.setLayoutParams(params);
|
||||
//
|
||||
//
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public TextViewBuilder center_xy() {
|
||||
// TableRow.LayoutParams params = new TableRow.LayoutParams();
|
||||
// params.gravity = Gravity.CENTER;
|
||||
// tv.setLayoutParams(params);
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public TextViewBuilder align_right() {
|
||||
tv.setGravity(Gravity.END);
|
||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder layout_wrap_wrap() {
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder layout_wrap_match() {
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder layout_match_wrap() {
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder layout_match_match() {
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder h1() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline1);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder h2() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline2);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder h3() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline3);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder h4() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline4);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder h5() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline5);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder h6() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder sub1() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder sub2() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle2);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextViewBuilder body1() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body1);
|
||||
return this;
|
||||
}
|
||||
public TextViewBuilder body2() {
|
||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body2);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public TextView build() {
|
||||
return tv;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 636 KiB |
|
After Width: | Height: | Size: 954 KiB |
@@ -17,23 +17,36 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/table"
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.ridgebotics.ridgescout.ui.views.CustomSpinnerView
|
||||
android:id="@+id/data_type_dropdown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="50dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/table"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.ridgebotics.ridgescout.ui.views.CustomSpinnerView
|
||||
android:id="@+id/data_type_dropdown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</TableLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -29,14 +29,38 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
tools:layout_editor_absoluteX="0dp" >
|
||||
|
||||
</com.ridgebotics.ridgescout.ui.views.TeamCard>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/tbaButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="3dp"
|
||||
android:layout_weight="1"
|
||||
android:text="View on TBA" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/statboticsButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="3dp"
|
||||
android:layout_weight="1"
|
||||
android:text="View on Statbotics" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Pit Data"
|
||||
android:textAlignment="center"
|
||||
android:textSize="24sp"
|
||||
android:textSize="35sp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/team_description2"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
@@ -49,6 +73,11 @@
|
||||
app:layout_constraintStart_toStartOf="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>
|
||||
|
||||
<TextView
|
||||
@@ -57,7 +86,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Match Data"
|
||||
android:textAlignment="center"
|
||||
android:textSize="24sp"
|
||||
android:textSize="35sp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/team_description2"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
@@ -115,9 +144,13 @@
|
||||
app:layout_constraintStart_toStartOf="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>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -30,13 +30,11 @@
|
||||
android:layout_height="54dp"
|
||||
android:layout_margin="2dp"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@drawable/ic_robologo"
|
||||
tools:visibility="visible" />
|
||||
tools:srcCompat="@drawable/ic_robologo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/field_option_name"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.11.1"
|
||||
asynclayoutinflator = "1.1.0"
|
||||
agp = "8.13.2"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.1.5"
|
||||
espressoCore = "3.5.1"
|
||||
@@ -11,13 +10,11 @@ lifecycleLivedataKtx = "2.6.1"
|
||||
lifecycleViewmodelKtx = "2.6.1"
|
||||
material3 = "1.3.1"
|
||||
navigationFragment = "2.6.0"
|
||||
navigationFragmentVersion = "2.8.9"
|
||||
navigationUi = "2.6.0"
|
||||
supportAnnotations = "28.0.0"
|
||||
preference = "1.2.1"
|
||||
|
||||
[libraries]
|
||||
asynclayoutinflator = { module = "androidx.asynclayoutinflator:asynclayoutinflator", version.ref = "asynclayoutinflator" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
@@ -28,7 +25,6 @@ lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-lived
|
||||
lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
|
||||
navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigationFragment" }
|
||||
navigation-fragment-v289 = { module = "androidx.navigation:navigation-fragment", version.ref = "navigationFragmentVersion" }
|
||||
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
|
||||
support-annotations = { group = "com.android.support", name = "support-annotations", version.ref = "supportAnnotations" }
|
||||
preference = { group = "androidx.preference", name = "preference", version.ref = "preference" }
|
||||
|
||||
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 493 KiB |
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 434 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 454 KiB |
@@ -17,7 +17,6 @@ dependencyResolutionManagement {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven ( url = "https://jitpack.io" )
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||