mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-09 08:38:03 -06:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79e8e7cbfc | |||
| 311dfcbd5d | |||
| fa47eb1aff | |||
| 93b58310bf | |||
| 859d3bc773 | |||
| 9136df04df | |||
| f281ff2f0a | |||
| 154e76fbf7 | |||
| ffaec948b4 | |||
| 2d3db09aae | |||
| 05a40e39c3 | |||
| 090a0579b9 | |||
| a30664000c | |||
| 1bae273abd | |||
| 5c2b1fef2e | |||
| dbba56e649 | |||
| 4aa31b620d | |||
| 890b879ef9 | |||
| 5279c085e1 | |||
| 41460fcd7e | |||
| 782fb73050 | |||
| 7e9954d78a | |||
| 65baecac35 | |||
| e278bc10a1 | |||
| 5d727cf359 | |||
| ae147771cb |
@@ -1,3 +1,9 @@
|
|||||||
|
# Python server
|
||||||
|
__pycache__/
|
||||||
|
metadata.json
|
||||||
|
api_key.txt
|
||||||
|
server_data/
|
||||||
|
|
||||||
# Gradle files
|
# Gradle files
|
||||||
.gradle/
|
.gradle/
|
||||||
build/
|
build/
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
[**Read the wiki**](https://github.com/Team4388/ScoutingApp2025/wiki)
|
[**Read the wiki**](https://github.com/Team4388/ScoutingApp2025/wiki)
|
||||||
|
|
||||||
[**Test Data**](https://github.com/Team4388/ScoutingApp2025/blob/main/2024week0-1728149849985.scoutbundle)
|
#### Features
|
||||||
|
|
||||||
#### Here is an overview of the main features currently included in the app:
|
|
||||||
- This project is written for Android! No need for some kind of janky laptop charging setup.
|
- This project is written for Android! No need for some kind of janky laptop charging setup.
|
||||||
- Similar to ScoutingPASS, there are many diffrent types of fields that can be used to collect data.
|
- Similar to ScoutingPASS, there are many diffrent types of fields that can be used to collect data.
|
||||||
- The app is designed to handle updates to the fields on the fly, without loosing any data!
|
- The app is designed to handle updates to the fields on the fly, without loosing any data!
|
||||||
@@ -20,17 +18,7 @@
|
|||||||
- Deployment on F-Droid
|
- Deployment on F-Droid
|
||||||
- Data cloud sync using an FTP server
|
- Data cloud sync using an FTP server
|
||||||
|
|
||||||
#### Things that are yet to be implemented:
|
|
||||||
- A page that lets users cross-compare scouting data between teams. (Compare)
|
|
||||||
- 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
|
|
||||||
- Scout error estimation using OPR-like calculation
|
|
||||||
- - Would most likely require Statbotics
|
|
||||||
|
|
||||||
### Screenshots
|
### Screenshots
|
||||||
|Match scouting interface|Field editor|Teams data viewer|
|
|Match scouting interface|Field editor|Teams data viewer|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
||||
|
||||
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
### TODO:
|
|
||||||
##### Scouting:
|
|
||||||
- Make an easier way to make game-specific UI elements
|
|
||||||
##### Data Analysis:
|
|
||||||
- Add analysis for the rest of the data types besides Tally
|
|
||||||
- Add a "scout note" system for scouters to contribute to the scouting report?
|
|
||||||
- Make data that has been marked for rescouting not processed in either by team or by type analysis.
|
|
||||||
##### Functionality:
|
|
||||||
- Rewrite FTP transfer to be over HTTP requests
|
|
||||||
- - Potentially using a python server or some other pre-existing file transfer over HTTP
|
|
||||||
- Delete file menu
|
|
||||||
- Make "Sync meta files" option only block uploading fields specifically.
|
|
||||||
##### UI:
|
|
||||||
- Update docs and README.md with new features
|
|
||||||
- Improve file status indicator for scouting
|
|
||||||
- - The autosave timeout can be significantly reduced, so the save indicator is not a necessity
|
|
||||||
- - A new system for the rescout indicator should be used.
|
|
||||||
- Improve UI elements for scouting data by team
|
|
||||||
- Field button in settings overlaps with other elements in some devices
|
|
||||||
|
|
||||||
### In Progress:
|
|
||||||
##### Scouting:
|
|
||||||
##### Data Analysis:
|
|
||||||
##### Functionality:
|
|
||||||
##### UI:
|
|
||||||
|
|
||||||
### Done:
|
|
||||||
##### Scouting:
|
|
||||||
##### Data Analysis:
|
|
||||||
##### Functionality:
|
|
||||||
##### UI:
|
|
||||||
@@ -44,8 +44,8 @@ android {
|
|||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
}
|
}
|
||||||
aaptOptions {
|
androidResources {
|
||||||
noCompress("tflite");
|
noCompress += listOf("tflite")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,10 +66,10 @@ dependencies {
|
|||||||
androidTestImplementation(libs.espresso.core)
|
androidTestImplementation(libs.espresso.core)
|
||||||
|
|
||||||
|
|
||||||
var camerax_version = "1.3.2"
|
var camerax_version = "1.4.2"
|
||||||
implementation("androidx.camera:camera-core:1.3.2")
|
implementation("androidx.camera:camera-core:${camerax_version}")
|
||||||
implementation("androidx.camera:camera-camera2:1.3.2")
|
implementation("androidx.camera:camera-camera2:${camerax_version}")
|
||||||
implementation("androidx.camera:camera-lifecycle:1.3.2")
|
implementation("androidx.camera:camera-lifecycle:${camerax_version}")
|
||||||
implementation("androidx.camera:camera-view:${camerax_version}")
|
implementation("androidx.camera:camera-view:${camerax_version}")
|
||||||
|
|
||||||
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
|
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class Fields {
|
|||||||
|
|
||||||
public static final FieldType[][] default_match_fields = new FieldType[][] {
|
public static final FieldType[][] default_match_fields = new FieldType[][] {
|
||||||
{
|
{
|
||||||
new FieldposType(uuid(),"Auto start pos", "Where does the robot start its auto?", new int[]{0,0}),
|
new FieldposType(uuid(),"Auto start pos", "Where does the robot start its auto?", FieldposType.DEFAULT_FIELD_IMAGE, new int[]{0,0}),
|
||||||
|
|
||||||
new TallyType(uuid(),"Auto L4 Coral", "How many coral did this robot score in L4 during auto?", 0),
|
new TallyType(uuid(),"Auto 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 L3 Coral", "How many coral did this robot score in L3 during auto?", 0),
|
||||||
@@ -42,12 +42,12 @@ public class Fields {
|
|||||||
new DropdownType(uuid(),"Auto Quality", "How did the robot drive during auto?", new String[]{"Smooth", "Jittery"}, 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 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 L4 Coral", "How many coral did this robot score in L4 during teleop?", 0),
|
||||||
new TallyType(uuid(),"Teleop L3 Coral", "How many coral did this robot score in L3 during auto?", 0),
|
new TallyType(uuid(),"Teleop L3 Coral", "How many coral did this robot score in L3 during teleop?", 0),
|
||||||
new TallyType(uuid(),"Teleop L2 Coral", "How many coral did this robot score in L2 during auto?", 0),
|
new TallyType(uuid(),"Teleop L2 Coral", "How many coral did this robot score in L2 during teleop?", 0),
|
||||||
new TallyType(uuid(),"Teleop L1 Coral", "How many coral did this robot score in L1 during auto?", 0),
|
new TallyType(uuid(),"Teleop L1 Coral", "How many coral did this robot score in L1 during teleop?", 0),
|
||||||
new TallyType(uuid(),"Teleop Processor Algae", "How many algae did this robot score in the Barge during auto?", 0),
|
new TallyType(uuid(),"Teleop Processor Algae", "How many algae did this robot score in the Barge during teleop?", 0),
|
||||||
new TallyType(uuid(),"Teleop Barge Algae", "How many algae did this robot score in the Barge during auto?", 0),
|
new TallyType(uuid(),"Teleop Barge Algae", "How many algae did this robot score in the Barge during teleop?", 0),
|
||||||
|
|
||||||
new CheckboxType(uuid(),"Upper Algae Removal", "Did the robot remove upper Algae?", 0),
|
new CheckboxType(uuid(),"Upper Algae Removal", "Did the robot remove upper Algae?", 0),
|
||||||
new CheckboxType(uuid(),"Lower Algae Removal", "Did the robot remove lower Algae?", 0),
|
new CheckboxType(uuid(),"Lower Algae Removal", "Did the robot remove lower Algae?", 0),
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.ridgebotics.ridgescout.scoutingData;
|
package com.ridgebotics.ridgescout.scoutingData;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
||||||
import com.ridgebotics.ridgescout.types.ScoutingArray;
|
import com.ridgebotics.ridgescout.types.ScoutingArray;
|
||||||
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
||||||
@@ -31,15 +33,15 @@ public class ScoutingDataWriter {
|
|||||||
switch (data[i].getValueType()){
|
switch (data[i].getValueType()){
|
||||||
case NUM:
|
case NUM:
|
||||||
bb.addInt((int) data[i].forceGetValue());
|
bb.addInt((int) data[i].forceGetValue());
|
||||||
System.out.println("Saved INT: " + data[i].getUUID() + ", ("+ data[i].get() +")");
|
Log.i(ScoutingDataWriter.class.toString(),"Saved INT: " + data[i].getUUID() + ", ("+ data[i].get() +")");
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
bb.addString((String) data[i].forceGetValue());
|
bb.addString((String) data[i].forceGetValue());
|
||||||
System.out.println("Saved STR: " + data[i].getUUID() + ", ("+ data[i].get() +")");
|
Log.i(ScoutingDataWriter.class.toString(), "Saved STR: " + data[i].getUUID() + ", ("+ data[i].get() +")");
|
||||||
break;
|
break;
|
||||||
case NUMARR:
|
case NUMARR:
|
||||||
bb.addIntArray((int[]) data[i].forceGetValue());
|
bb.addIntArray((int[]) data[i].forceGetValue());
|
||||||
System.out.println("Saved INT Array: " + data[i].getUUID() + ", ("+ Arrays.toString((int[]) data[i].get()) +")");
|
Log.i(ScoutingDataWriter.class.toString(), "Saved INT Array: " + data[i].getUUID() + ", ("+ Arrays.toString((int[]) data[i].get()) +")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byte[] bytes = bb.build();
|
byte[] bytes = bb.build();
|
||||||
@@ -58,61 +60,57 @@ public class ScoutingDataWriter {
|
|||||||
public ScoutingArray data;
|
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);
|
byte[] bytes = FileEditor.readFile(filename);
|
||||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
ArrayList<BuiltByteParser.parsedObject> objects = bbp.parse();
|
||||||
RawDataType[] rawDataTypes = new RawDataType[objects.size()-2];
|
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.addSimpleError("Error loading " + filename);
|
||||||
AlertManager.error(new BuiltByteParser.byteParsingExeption("Field version (" +version + ") is too recent as compared to latest version (" + (values.length-1) + ")!"));
|
throw new BuiltByteParser.byteParsingExeption("Field version (" +version + ") is too recent as compared to latest version (" + (values.length-1) + ")!");
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// System.out.println(version);
|
// 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++){
|
for(int i = 0; i < values[version].length; i++){
|
||||||
switch (objects.get(i+2).getType()){
|
switch (objects.get(i+2).getType()){
|
||||||
case 1: // Int
|
case 1: // Int
|
||||||
rawDataTypes[i] = IntType.newNull(values[version][i].UUID);
|
rawDataTypes[i] = IntType.newNull(values[version][i].UUID);
|
||||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||||
System.out.println("Loaded INT: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded INT: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
||||||
break;
|
break;
|
||||||
case 2: // String
|
case 2: // String
|
||||||
rawDataTypes[i] = StringType.newNull(values[version][i].UUID);
|
rawDataTypes[i] = StringType.newNull(values[version][i].UUID);
|
||||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||||
System.out.println("Loaded STR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded STR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ rawDataTypes[i].get() +")");
|
||||||
break;
|
break;
|
||||||
case 3: // Int array
|
case 3: // Int array
|
||||||
rawDataTypes[i] = IntArrType.newNull(values[version][i].UUID);
|
rawDataTypes[i] = IntArrType.newNull(values[version][i].UUID);
|
||||||
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
rawDataTypes[i].forceSetValue(objects.get(i+2).get());
|
||||||
System.out.println("Loaded intARR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ Arrays.toString((int[]) rawDataTypes[i].get()) +")");
|
Log.i(ParsedScoutingDataResult.class.toString(),"Loaded intARR: " + values[version][i].name + " (" + values[version][i].UUID + ") " + ", ("+ Arrays.toString((int[]) rawDataTypes[i].get()) +")");
|
||||||
break;
|
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
|
// A function that takes in a list of names seperated by commas, and adds a name if it is not included
|
||||||
|
|||||||
@@ -0,0 +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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.ridgebotics.ridgescout.types;
|
package com.ridgebotics.ridgescout.types;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.scoutingData.transfer.CreateTransferType;
|
import com.ridgebotics.ridgescout.scoutingData.transfer.CreateTransferType;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.transfer.DirectTransferType;
|
import com.ridgebotics.ridgescout.scoutingData.transfer.DirectTransferType;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
||||||
@@ -44,7 +46,7 @@ public class ScoutingArray {
|
|||||||
}
|
}
|
||||||
this.array = new_values;
|
this.array = new_values;
|
||||||
version++;
|
version++;
|
||||||
System.out.println("Updated to " + version);
|
Log.i(getClass().toString(),"Updated to " + version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,13 @@ import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
|||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
// Class to contain data for an entire event.
|
// Class to contain data for an entire event.
|
||||||
// Easily encoded and decoded to binary format.
|
// Easily encoded and decoded to binary format.
|
||||||
public class frcEvent {
|
public class frcEvent {
|
||||||
|
|
||||||
public static final int typecode = 254;
|
|
||||||
public String eventCode;
|
public String eventCode;
|
||||||
public String name;
|
public String name;
|
||||||
public ArrayList<frcMatch> matches;
|
public ArrayList<frcMatch> matches;
|
||||||
@@ -134,29 +133,29 @@ public class frcEvent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public
|
|
||||||
|
|
||||||
// Returns the soonest match that there will be all the possible upcoming data on other teams
|
// Returns the soonest match that there will be all the possible upcoming data on other teams
|
||||||
public void getReportMatches(int ourTeamNum){
|
public int getMostInformedBy(int ourTeamNum, int curMatch){
|
||||||
frcMatch[] teamMatches = event.getTeamMatches(ourTeamNum);
|
frcMatch teamMatch = getNextTeamMatch(ourTeamNum, curMatch);
|
||||||
|
|
||||||
for(int i = 0; i < teamMatches.length; i++){
|
int maxMatch = Integer.MIN_VALUE;
|
||||||
int maxMatch = -1;
|
|
||||||
for(int a = 0; a < 6; a++){
|
|
||||||
int teamNum;
|
|
||||||
if(a < 3)
|
|
||||||
teamNum = teamMatches[i].redAlliance[a];
|
|
||||||
else
|
|
||||||
teamNum = teamMatches[i].blueAlliance[a-3];
|
|
||||||
|
|
||||||
if(teamNum == ourTeamNum)
|
for(int a = 0; a < 6; a++){
|
||||||
continue;
|
int teamNum;
|
||||||
|
if(a < 3)
|
||||||
|
teamNum = teamMatch.redAlliance[a];
|
||||||
|
else
|
||||||
|
teamNum = teamMatch.blueAlliance[a-3];
|
||||||
|
|
||||||
int matchNum = event.getMostRecentTeamMatch(teamNum, teamMatches[i].matchIndex);
|
if(teamNum == ourTeamNum)
|
||||||
if(maxMatch < matchNum)
|
continue;
|
||||||
maxMatch = matchNum;
|
|
||||||
}
|
int matchNum = event.getMostRecentTeamMatch(teamNum, teamMatch.matchIndex);
|
||||||
|
if(maxMatch < matchNum)
|
||||||
|
maxMatch = matchNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return maxMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public frcTeam getTeamByNum(int teamNum){
|
public frcTeam getTeamByNum(int teamNum){
|
||||||
@@ -168,6 +167,26 @@ public class frcEvent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<frcTeam> getTeamsSorted() {
|
||||||
|
int[] teamNums = new int[teams.size()];
|
||||||
|
|
||||||
|
for(int i = 0 ; i < teams.size(); i++){
|
||||||
|
teamNums[i] = teams.get(i).teamNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arrays.sort(teamNums);
|
||||||
|
|
||||||
|
List<frcTeam> list = new ArrayList<>();
|
||||||
|
|
||||||
|
for(int i = 0; i < teams.size(); i++){
|
||||||
|
frcTeam team = getTeamByNum(teamNums[i]);
|
||||||
|
assert team != null;
|
||||||
|
list.add(team);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean getIsBlueAlliance(int teamNum, int matchNum){
|
public boolean getIsBlueAlliance(int teamNum, int matchNum){
|
||||||
return getIsBlueAlliance(teamNum, matches.get(matchNum));
|
return getIsBlueAlliance(teamNum, matches.get(matchNum));
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.github.mikephil.charting.data.LineDataSet;
|
|||||||
import com.github.mikephil.charting.data.PieData;
|
import com.github.mikephil.charting.data.PieData;
|
||||||
import com.github.mikephil.charting.data.PieDataSet;
|
import com.github.mikephil.charting.data.PieDataSet;
|
||||||
import com.github.mikephil.charting.data.PieEntry;
|
import com.github.mikephil.charting.data.PieEntry;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -105,16 +106,14 @@ public class DropdownType extends FieldType {
|
|||||||
|
|
||||||
public void add_individual_view(LinearLayout parent, RawDataType data){
|
public void add_individual_view(LinearLayout parent, RawDataType data){
|
||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
TextView tv = new TextView(parent.getContext());
|
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
parent.addView(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
new TextViewBuilder(parent.getContext(), text_options[(int) data.get()])
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.layout_match_wrap()
|
||||||
));
|
.padding(20)
|
||||||
tv.setPadding(20,20,20,20);
|
.size(18)
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
.align_center()
|
||||||
tv.setText(text_options[(int) data.get()]);
|
.build());
|
||||||
tv.setTextSize(18);
|
|
||||||
parent.addView(tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import com.github.mikephil.charting.components.Legend;
|
|||||||
import com.github.mikephil.charting.data.Entry;
|
import com.github.mikephil.charting.data.Entry;
|
||||||
import com.github.mikephil.charting.data.LineData;
|
import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
|
import com.ridgebotics.ridgescout.R;
|
||||||
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
||||||
import com.ridgebotics.ridgescout.types.data.IntArrType;
|
import com.ridgebotics.ridgescout.types.data.IntArrType;
|
||||||
import com.ridgebotics.ridgescout.ui.views.FieldPosView;
|
import com.ridgebotics.ridgescout.ui.views.FieldPosView;
|
||||||
@@ -31,14 +32,58 @@ import java.util.Map;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class FieldposType extends FieldType {
|
public class FieldposType extends FieldType {
|
||||||
|
public static final FieldImage DEFAULT_FIELD_IMAGE = FieldImage.F2025;
|
||||||
|
public enum FieldImage {
|
||||||
|
F2025(0, "2025", R.drawable.field_2025, R.drawable.field_2025_flipped),
|
||||||
|
F2025_analogous(1, "2025 - analogous", R.drawable.field_2025_analogous);
|
||||||
|
|
||||||
|
|
||||||
|
public int index, resId_normal, resId_flipped;
|
||||||
|
public String name;
|
||||||
|
public boolean flippable;
|
||||||
|
|
||||||
|
FieldImage(int index, String name, int resId) {
|
||||||
|
this.index = index;
|
||||||
|
this.name = name;
|
||||||
|
this.resId_normal = resId;
|
||||||
|
this.resId_flipped = resId;
|
||||||
|
this.flippable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldImage(int index, String name, int resId_normal, int resId_flipped) {
|
||||||
|
this.index = index;
|
||||||
|
this.name = name;
|
||||||
|
this.resId_normal = resId_normal;
|
||||||
|
this.resId_flipped = resId_flipped;
|
||||||
|
this.flippable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldImage from_index(int index) {
|
||||||
|
return FieldImage.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get_index() {
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldImage fieldImage;
|
||||||
|
|
||||||
|
|
||||||
public int get_byte_id() {return fieldposType;}
|
public int get_byte_id() {return fieldposType;}
|
||||||
public inputTypes getInputType(){return inputTypes.FIELDPOS;}
|
public inputTypes getInputType(){return inputTypes.FIELDPOS;}
|
||||||
public RawDataType.valueTypes getValueType(){return RawDataType.valueTypes.NUM;}
|
public RawDataType.valueTypes getValueType(){return RawDataType.valueTypes.NUM;}
|
||||||
public Object get_fallback_value(){return 0;}
|
public Object get_fallback_value(){return 0;}
|
||||||
public FieldposType(){}
|
public FieldposType(){}
|
||||||
public String get_type_name(){return "Field Pos";}
|
public String get_type_name(){return "Field Pos";}
|
||||||
public FieldposType(String UUID, String name, String description, int[] default_value){
|
public FieldposType(String UUID, String name, String description, FieldImage fieldImage, int[] default_value){
|
||||||
super(UUID, name, description);
|
super(UUID, name, description);
|
||||||
|
this.fieldImage = fieldImage;
|
||||||
this.default_value = default_value;
|
this.default_value = default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +92,14 @@ public class FieldposType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
public void encodeData(ByteBuilder bb) throws ByteBuilder.buildingException {
|
public void encodeData(ByteBuilder bb) throws ByteBuilder.buildingException {
|
||||||
|
bb.addInt(this.fieldImage.get_index());
|
||||||
bb.addIntArray((int[]) default_value);
|
bb.addIntArray((int[]) default_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeData(ArrayList<BuiltByteParser.parsedObject> objects) {
|
public void decodeData(ArrayList<BuiltByteParser.parsedObject> objects) {
|
||||||
default_value = objects.get(0).get();
|
fieldImage = FieldImage.from_index((int) objects.get(0).get());
|
||||||
|
default_value = objects.get(1).get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -65,6 +113,7 @@ public class FieldposType extends FieldType {
|
|||||||
onUpdate.apply(new IntArrType(name, pos));
|
onUpdate.apply(new IntArrType(name, pos));
|
||||||
});
|
});
|
||||||
setViewValue(default_value);
|
setViewValue(default_value);
|
||||||
|
field.setFieldImage(fieldImage);
|
||||||
return field;
|
return field;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -102,6 +151,7 @@ public class FieldposType extends FieldType {
|
|||||||
FieldPosView fp = new FieldPosView(parent.getContext());
|
FieldPosView fp = new FieldPosView(parent.getContext());
|
||||||
fp.setEnabled(false);
|
fp.setEnabled(false);
|
||||||
fp.setPos((int[]) data.get());
|
fp.setPos((int[]) data.get());
|
||||||
|
fp.setFieldImage(this.fieldImage);
|
||||||
|
|
||||||
parent.addView(fp);
|
parent.addView(fp);
|
||||||
}
|
}
|
||||||
@@ -113,54 +163,13 @@ public class FieldposType extends FieldType {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static float calculateMean(int[] data) {
|
|
||||||
float sum = 0;
|
|
||||||
for (int value : data) {
|
|
||||||
sum += (float) value;
|
|
||||||
}
|
|
||||||
return sum / data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float calculateStandardDeviation(int[] data, float mean) {
|
|
||||||
float sum = 0;
|
|
||||||
for (int value : data) {
|
|
||||||
sum += (float) Math.pow((float) value - mean, 2);
|
|
||||||
}
|
|
||||||
return (float) Math.sqrt(sum / (data.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Entry> generateNormalDistribution(float mean, float stdDev, int count, int scale) {
|
|
||||||
List<Entry> entries = new ArrayList<>();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
float y = (float) ((1 / (stdDev * Math.sqrt(2 * Math.PI)))
|
|
||||||
* Math.exp(-0.5 * Math.pow(((float) i - mean) / stdDev, 2)));
|
|
||||||
entries.add(new Entry((float) i, y*scale)); // Scale y for visibility
|
|
||||||
}
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int findMin(RawDataType[] data){
|
|
||||||
int min = (int)data[0].get();
|
|
||||||
for(int i = 1; i < data.length; i++)
|
|
||||||
if((int)data[i].get() < min)
|
|
||||||
min = (int)data[i].get();
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int findMax(RawDataType[] data){
|
|
||||||
int max = (int)data[0].get();
|
|
||||||
for(int i = 1; i < data.length; i++)
|
|
||||||
if((int)data[i].get() > max)
|
|
||||||
max = (int)data[i].get();
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add_compiled_view(LinearLayout parent, RawDataType[] data){
|
public void add_compiled_view(LinearLayout parent, RawDataType[] data){
|
||||||
MultiFieldPosView mfp = new MultiFieldPosView(parent.getContext());
|
MultiFieldPosView mfp = new MultiFieldPosView(parent.getContext());
|
||||||
for(int i = 0; i < data.length; i++){
|
for(int i = 0; i < data.length; i++){
|
||||||
if(data[i].isNull()) continue;
|
if(data[i].isNull()) continue;
|
||||||
mfp.addPos((int[]) data[i].get());
|
mfp.addPos((int[]) data[i].get());
|
||||||
}
|
}
|
||||||
|
mfp.setFieldImage(fieldImage);
|
||||||
parent.addView(mfp);
|
parent.addView(mfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.ridgebotics.ridgescout.types.data.RawDataType;
|
|||||||
import com.ridgebotics.ridgescout.types.data.IntType;
|
import com.ridgebotics.ridgescout.types.data.IntType;
|
||||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||||
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
import com.ridgebotics.ridgescout.utility.ByteBuilder;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -118,16 +119,11 @@ public class NumberType extends FieldType {
|
|||||||
|
|
||||||
public void add_individual_view(LinearLayout parent, RawDataType data){
|
public void add_individual_view(LinearLayout parent, RawDataType data){
|
||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
|
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
||||||
TextView tv = new TextView(parent.getContext());
|
.layout_match_wrap()
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(24)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText(String.valueOf((int) data.get()));
|
|
||||||
tv.setTextSize(24);
|
|
||||||
parent.addView(tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.github.mikephil.charting.components.Legend;
|
|||||||
import com.github.mikephil.charting.data.Entry;
|
import com.github.mikephil.charting.data.Entry;
|
||||||
import com.github.mikephil.charting.data.LineData;
|
import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -103,16 +104,11 @@ public class TallyType extends FieldType {
|
|||||||
|
|
||||||
public void add_individual_view(LinearLayout parent, RawDataType data){
|
public void add_individual_view(LinearLayout parent, RawDataType data){
|
||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
|
parent.addView(new TextViewBuilder(parent.getContext(), String.valueOf((int) data.get()))
|
||||||
TextView tv = new TextView(parent.getContext());
|
.layout_match_wrap()
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(24)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText(String.valueOf((int) data.get()));
|
|
||||||
tv.setTextSize(24);
|
|
||||||
parent.addView(tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -344,16 +340,12 @@ public class TallyType extends FieldType {
|
|||||||
row = new TableRow(parent.getContext());
|
row = new TableRow(parent.getContext());
|
||||||
CandlestickView view = views.get(i);
|
CandlestickView view = views.get(i);
|
||||||
|
|
||||||
TextView teamNum = new TextView(parent.getContext());
|
row.addView(new TextViewBuilder(parent.getContext(), String.valueOf(view.teamNum))
|
||||||
TableRow.LayoutParams params = new TableRow.LayoutParams();
|
.align_center()
|
||||||
params.gravity = Gravity.CENTER;
|
.padding(10)
|
||||||
teamNum.setLayoutParams(params);
|
.h6()
|
||||||
teamNum.setPadding(10,10,10,10);
|
.build());
|
||||||
teamNum.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6);
|
|
||||||
teamNum.setText(String.valueOf(view.teamNum));
|
|
||||||
|
|
||||||
|
|
||||||
row.addView(teamNum);
|
|
||||||
row.addView(view);
|
row.addView(view);
|
||||||
|
|
||||||
parent.addView(row);
|
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.Entry;
|
||||||
import com.github.mikephil.charting.data.LineData;
|
import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -112,15 +113,11 @@ public class TextType extends FieldType {
|
|||||||
|
|
||||||
public void add_individual_view(LinearLayout parent, RawDataType data){
|
public void add_individual_view(LinearLayout parent, RawDataType data){
|
||||||
if(data.isNull()) return;
|
if(data.isNull()) return;
|
||||||
TextView tv = new TextView(parent.getContext());
|
parent.addView(new TextViewBuilder(parent.getContext(), (String) data.get())
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.layout_match_wrap()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.align_center()
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.size(18)
|
||||||
));
|
.build());
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText((String) data.get());
|
|
||||||
tv.setTextSize(18);
|
|
||||||
parent.addView(tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -144,25 +141,20 @@ public class TextType extends FieldType {
|
|||||||
positive_mean = 0;
|
positive_mean = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
positive_text = new TextView(parent.getContext());
|
positive_text = new TextViewBuilder(parent.getContext())
|
||||||
positive_text.setLayoutParams(new FrameLayout.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(20)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build();
|
||||||
));
|
|
||||||
positive_text.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
positive_text.setTextSize(20);
|
|
||||||
parent.addView(positive_text);
|
parent.addView(positive_text);
|
||||||
|
|
||||||
for (int i = 0; i < data.length; i++){
|
for (int i = 0; i < data.length; i++){
|
||||||
if (!data[i].isNull()) {
|
if (!data[i].isNull()) {
|
||||||
SentimentAnalysis.analyse((String) data[i].get(), new SentimentAnalysis.resultCallback() {
|
SentimentAnalysis.analyse((String) data[i].get(), sentiment -> {
|
||||||
@Override
|
positive_mean += sentiment;
|
||||||
public void onFinish(float sentiment) {
|
count++;
|
||||||
positive_mean += sentiment;
|
|
||||||
count++;
|
|
||||||
|
|
||||||
positive_text.setText("Sentiment: " + (positive_mean / count));
|
positive_text.setText("Sentiment: " + (positive_mean / count));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import static com.ridgebotics.ridgescout.utility.DataManager.rescout_list;
|
|||||||
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -57,13 +58,13 @@ public class FieldDataFragment extends Fragment {
|
|||||||
for (int teamIndex = 0; teamIndex < event.teams.size(); teamIndex++) {
|
for (int teamIndex = 0; teamIndex < event.teams.size(); teamIndex++) {
|
||||||
int teamNum = event.teams.get(teamIndex).teamNumber;
|
int teamNum = event.teams.get(teamIndex).teamNumber;
|
||||||
List<String> filenames = new ArrayList<>(List.of(FileEditor.getMatchesByTeamNum(evcode, 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<>();
|
ArrayList<RawDataType> teamData = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < filenames.size(); i++) {
|
for (int i = 0; i < filenames.size(); i++) {
|
||||||
try {
|
try {
|
||||||
System.out.println("Loading: " + filenames.get(i));
|
Log.i(getClass().toString(), "Loading: " + filenames.get(i));
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filenames.get(i), match_values, match_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filenames.get(i), match_values, match_transferValues);
|
||||||
if (psda.data.array[fieldIndex] != null && psda.data.array[fieldIndex].get() != null && !psda.data.array[fieldIndex].isNull())
|
if (psda.data.array[fieldIndex] != null && psda.data.array[fieldIndex].get() != null && !psda.data.array[fieldIndex].isNull())
|
||||||
teamData.add(psda.data.array[fieldIndex]);
|
teamData.add(psda.data.array[fieldIndex]);
|
||||||
@@ -75,7 +76,7 @@ public class FieldDataFragment extends Fragment {
|
|||||||
data.put(teamNum, teamData);
|
data.put(teamNum, teamData);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Finished!");
|
Log.i(getClass().toString(), "Finished!");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ 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_transferValues;
|
||||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -23,6 +25,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentDataTeamsBinding;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||||
@@ -30,6 +33,7 @@ import com.ridgebotics.ridgescout.types.data.RawDataType;
|
|||||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -66,38 +70,37 @@ public class TeamsFragment extends Fragment {
|
|||||||
loadTeam(index);
|
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());
|
loadTeam(SettingsManager.getTeamsDataMode());
|
||||||
|
|
||||||
return binding.getRoot();
|
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) {
|
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);
|
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_pit_data(team);}catch(Exception e){AlertManager.error(e);}
|
||||||
try {add_match_data(team, mode);}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();
|
binding.pitArea.removeAllViews();
|
||||||
final String filename = evcode+"-"+team.teamNumber+".pitscoutdata";
|
final String filename = evcode+"-"+team.teamNumber+".pitscoutdata";
|
||||||
|
|
||||||
@@ -117,49 +120,34 @@ public class TeamsFragment extends Fragment {
|
|||||||
// ll.addView(new MaterialDivider(getContext()));
|
// ll.addView(new MaterialDivider(getContext()));
|
||||||
|
|
||||||
if(!FileEditor.fileExist(filename)){
|
if(!FileEditor.fileExist(filename)){
|
||||||
TextView tv = new TextView(getContext());
|
binding.pitArea.addView(new TextViewBuilder(getContext(), "No pit data has been collected!")
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.layout_match_wrap().align_center().size(23).build());
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||||
|
|
||||||
TextView tv = new TextView(getContext());
|
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
binding.pitArea.addView(new TextViewBuilder(getContext(), "Pit scouting by " + psda.username)
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.layout_match_wrap()
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.padding(0, 20, 0, 5)
|
||||||
));
|
.align_center()
|
||||||
tv.setPadding(0, 20, 0, 5);
|
.size(30)
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
.build()
|
||||||
tv.setText("Pit scouting by " + psda.username);
|
);
|
||||||
tv.setTextSize(30);
|
|
||||||
binding.pitArea.addView(tv);
|
|
||||||
|
|
||||||
for (int a = 0; a < psda.data.array.length; a++) {
|
for (int a = 0; a < psda.data.array.length; a++) {
|
||||||
tv = new TextView(getContext());
|
TextViewBuilder tvb = new TextViewBuilder(getContext(), pit_latest_values[a].name)
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.layout_match_wrap()
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.size(25);
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText(pit_latest_values[a].name);
|
|
||||||
tv.setTextSize(25);
|
|
||||||
|
|
||||||
if(psda.data.array[a].isNull()){
|
if(psda.data.array[a].isNull()){
|
||||||
tv.setBackgroundColor(toggletitle_unselected);
|
tvb.tv.setBackgroundColor(toggletitle_unselected);
|
||||||
tv.setTextColor(toggletitle_black_background);
|
tvb.tv.setTextColor(toggletitle_black_background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.pitArea.addView(tvb.build());
|
||||||
|
|
||||||
binding.pitArea.addView(tv);
|
|
||||||
|
|
||||||
|
|
||||||
pit_latest_values[a].add_individual_view(binding.pitArea, psda.data.array[a]);
|
pit_latest_values[a].add_individual_view(binding.pitArea, psda.data.array[a]);
|
||||||
@@ -175,15 +163,11 @@ public class TeamsFragment extends Fragment {
|
|||||||
String[] files = FileEditor.getMatchesByTeamNum(evcode, team.teamNumber);
|
String[] files = FileEditor.getMatchesByTeamNum(evcode, team.teamNumber);
|
||||||
|
|
||||||
if(files.length == 0){
|
if(files.length == 0){
|
||||||
TextView tv = new TextView(getContext());
|
binding.matchArea.addView(new TextViewBuilder(getContext(), "No match data has been collected!")
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.layout_match_wrap()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.align_center()
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.size(23)
|
||||||
));
|
.build());
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText("No match data has been collected!");
|
|
||||||
tv.setTextSize(23);
|
|
||||||
binding.matchArea.addView(tv);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,33 +220,28 @@ public class TeamsFragment extends Fragment {
|
|||||||
|
|
||||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[matchIndex], match_values, match_transferValues);
|
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(files[matchIndex], match_values, match_transferValues);
|
||||||
|
|
||||||
TextView tv = new TextView(getContext());
|
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
binding.matchArea.addView(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
new TextViewBuilder(getContext(), "M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.align_center()
|
||||||
));
|
.size(30)
|
||||||
tv.setPadding(0, 40, 0, 5);
|
.padding(0,0,40,5)
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
.build()
|
||||||
tv.setText("M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username);
|
|
||||||
tv.setTextSize(30);
|
);
|
||||||
binding.matchArea.addView(tv);
|
|
||||||
|
|
||||||
for (int i = 0; i < psda.data.array.length; i++) {
|
for (int i = 0; i < psda.data.array.length; i++) {
|
||||||
tv = new TextView(getContext());
|
TextViewBuilder tv = new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(25);
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText(match_latest_values[i].name);
|
|
||||||
tv.setTextSize(25);
|
|
||||||
|
|
||||||
if (psda.data.array[i].isNull()) {
|
if (psda.data.array[i].isNull()) {
|
||||||
tv.setBackgroundColor(toggletitle_unselected);
|
tv.tv.setBackgroundColor(toggletitle_unselected);
|
||||||
tv.setTextColor(toggletitle_black_background);
|
tv.tv.setTextColor(toggletitle_black_background);
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.matchArea.addView(tv);
|
binding.matchArea.addView(tv.build());
|
||||||
|
|
||||||
|
|
||||||
if(psda.data.array[i] != null)
|
if(psda.data.array[i] != null)
|
||||||
@@ -294,16 +273,14 @@ public class TeamsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < match_latest_values.length; i++){
|
for(int i = 0; i < match_latest_values.length; i++){
|
||||||
TextView tv = new TextView(getContext());
|
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
binding.matchArea.addView(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.align_center()
|
||||||
));
|
.padding(0, 0, 20, 5)
|
||||||
tv.setPadding(0, 20, 0, 5);
|
.size(30)
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
.build()
|
||||||
tv.setText(match_latest_values[i].name);
|
);
|
||||||
tv.setTextSize(30);
|
|
||||||
binding.matchArea.addView(tv);
|
|
||||||
|
|
||||||
if(data[i] != null)
|
if(data[i] != null)
|
||||||
match_latest_values[i].add_compiled_view(binding.matchArea, data[i]);
|
match_latest_values[i].add_compiled_view(binding.matchArea, data[i]);
|
||||||
@@ -329,19 +306,18 @@ public class TeamsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < match_latest_values.length; i++){
|
for(int i = 0; i < match_latest_values.length; i++){
|
||||||
TextView tv = new TextView(getContext());
|
|
||||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
binding.matchArea.addView(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
new TextViewBuilder(getContext(), match_latest_values[i].name)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.align_center()
|
||||||
));
|
.size(30)
|
||||||
tv.setPadding(0, 20, 0, 5);
|
.padding(0,0,20,5)
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
.build()
|
||||||
tv.setText(match_latest_values[i].name);
|
);
|
||||||
tv.setTextSize(30);
|
|
||||||
binding.matchArea.addView(tv);
|
|
||||||
|
|
||||||
if(data[i] != null)
|
if(data[i] != null)
|
||||||
match_latest_values[i].add_history_view(binding.matchArea, data[i]);
|
match_latest_values[i].add_history_view(binding.matchArea, data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -29,6 +30,7 @@ import com.ridgebotics.ridgescout.utility.FileEditor;
|
|||||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -58,11 +60,10 @@ public class EventFragment extends Fragment {
|
|||||||
add_match_scouting(event);
|
add_match_scouting(event);
|
||||||
}
|
}
|
||||||
private void addTableText(TableRow tr, String textStr){
|
private void addTableText(TableRow tr, String textStr){
|
||||||
TextView text = new TextView(getContext());
|
tr.addView(new TextViewBuilder(getContext(), textStr)
|
||||||
text.setTextSize(18);
|
.align_center()
|
||||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
.size(18)
|
||||||
text.setText(textStr);
|
.build());
|
||||||
tr.addView(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add_pit_scouting(frcEvent event){
|
public void add_pit_scouting(frcEvent event){
|
||||||
@@ -93,33 +94,32 @@ public class EventFragment extends Fragment {
|
|||||||
tr = new TableRow(getContext());
|
tr = new TableRow(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView text = new TextView(getContext());
|
TextViewBuilder text = new TextViewBuilder(getContext(), String.valueOf(num))
|
||||||
text.setTextSize(18);
|
.size(18)
|
||||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
.align_center();
|
||||||
|
|
||||||
text.setText(String.valueOf(num));
|
|
||||||
final String filename = event.eventCode + "-" + num + ".pitscoutdata";
|
final String filename = event.eventCode + "-" + num + ".pitscoutdata";
|
||||||
if(FileEditor.fileExist(filename)){
|
if(FileEditor.fileExist(filename)){
|
||||||
final boolean[] rescout = {DataManager.rescout_list.contains(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];
|
rescout[0] = !rescout[0];
|
||||||
if(rescout[0]) {
|
if(rescout[0]) {
|
||||||
text.setBackgroundColor(color_rescout);
|
text.tv.setBackgroundColor(color_rescout);
|
||||||
DataManager.rescout_list.add(filename);
|
DataManager.rescout_list.add(filename);
|
||||||
}else{
|
}else{
|
||||||
text.setBackgroundColor(color_found);
|
text.tv.setBackgroundColor(color_found);
|
||||||
DataManager.rescout_list.remove(filename);
|
DataManager.rescout_list.remove(filename);
|
||||||
}
|
}
|
||||||
DataManager.save_rescout_list();
|
DataManager.save_rescout_list();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
text.setBackgroundColor(color_not_found);
|
text.tv.setBackgroundColor(color_not_found);
|
||||||
}
|
}
|
||||||
tr.addView(text);
|
tr.addView(text.build());
|
||||||
}
|
}
|
||||||
if(tr != null)
|
if(tr != null)
|
||||||
binding.teamsTable.addView(tr);
|
binding.teamsTable.addView(tr);
|
||||||
@@ -152,10 +152,6 @@ public class EventFragment extends Fragment {
|
|||||||
addTableText(tr, String.valueOf(match.matchIndex));
|
addTableText(tr, String.valueOf(match.matchIndex));
|
||||||
//
|
//
|
||||||
for(int i=0;i<6;i++){
|
for(int i=0;i<6;i++){
|
||||||
TextView text = new TextView(getContext());
|
|
||||||
text.setTextSize(18);
|
|
||||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
|
||||||
|
|
||||||
int team_num;
|
int team_num;
|
||||||
String alliance_position;
|
String alliance_position;
|
||||||
|
|
||||||
@@ -167,20 +163,23 @@ public class EventFragment extends Fragment {
|
|||||||
alliance_position = "blue-"+(i-2);
|
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";
|
final String filename = event.eventCode + "-" + match.matchIndex + "-" + alliance_position + "-" + team_num + ".matchscoutdata";
|
||||||
if(FileEditor.fileExist(filename)){
|
if(FileEditor.fileExist(filename)){
|
||||||
final boolean[] rescout = {DataManager.rescout_list.contains(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];
|
rescout[0] = !rescout[0];
|
||||||
if(rescout[0]) {
|
if(rescout[0]) {
|
||||||
text.setBackgroundColor(color_rescout);
|
text.tv.setBackgroundColor(color_rescout);
|
||||||
DataManager.rescout_list.add(filename);
|
DataManager.rescout_list.add(filename);
|
||||||
}else{
|
}else{
|
||||||
text.setBackgroundColor(color_found);
|
text.tv.setBackgroundColor(color_found);
|
||||||
DataManager.rescout_list.remove(filename);
|
DataManager.rescout_list.remove(filename);
|
||||||
}
|
}
|
||||||
DataManager.save_rescout_list();
|
DataManager.save_rescout_list();
|
||||||
@@ -188,9 +187,9 @@ public class EventFragment extends Fragment {
|
|||||||
});
|
});
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
text.setBackgroundColor(color_not_found);
|
text.tv.setBackgroundColor(color_not_found);
|
||||||
}
|
}
|
||||||
tr.addView(text);
|
tr.addView(text.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.matchTable.addView(tr);
|
binding.matchTable.addView(tr);
|
||||||
@@ -276,7 +275,7 @@ public class EventFragment extends Fragment {
|
|||||||
builder.setPositiveButton("OK", (dialogInterface, i) -> {
|
builder.setPositiveButton("OK", (dialogInterface, i) -> {
|
||||||
|
|
||||||
int index = dropdown.getIndex();
|
int index = dropdown.getIndex();
|
||||||
System.out.println(index);
|
Log.i(getClass().toString(), String.valueOf(index));
|
||||||
if(!(index >= 0 && index < teamNums.size())) return;
|
if(!(index >= 0 && index < teamNums.size())) return;
|
||||||
|
|
||||||
event.teams.remove(index);
|
event.teams.remove(index);
|
||||||
|
|||||||
+29
-23
@@ -9,6 +9,7 @@ import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -20,6 +21,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
|
|
||||||
import com.google.android.material.divider.MaterialDivider;
|
import com.google.android.material.divider.MaterialDivider;
|
||||||
import com.ridgebotics.ridgescout.ui.views.ToggleTitleView;
|
import com.ridgebotics.ridgescout.ui.views.ToggleTitleView;
|
||||||
|
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingMatchBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentScoutingMatchBinding;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||||
@@ -31,6 +33,7 @@ import com.ridgebotics.ridgescout.utility.AlertManager;
|
|||||||
import com.ridgebotics.ridgescout.utility.AutoSaveManager;
|
import com.ridgebotics.ridgescout.utility.AutoSaveManager;
|
||||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
// Fragment for match scouting data editing.
|
// Fragment for match scouting data editing.
|
||||||
public class MatchScoutingFragment extends Fragment {
|
public class MatchScoutingFragment extends Fragment {
|
||||||
@@ -48,24 +51,27 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
alliance_position = SettingsManager.getAllyPos();
|
alliance_position = SettingsManager.getAllyPos();
|
||||||
username = SettingsManager.getUsername();
|
username = SettingsManager.getUsername();
|
||||||
|
|
||||||
binding.username.setText(username);
|
binding.bindicator.setUsername(username);
|
||||||
binding.alliancePosText.setText(alliance_position);
|
binding.bindicator.setAlliancePos(alliance_position);
|
||||||
|
binding.bindicator.bringToFront();
|
||||||
|
|
||||||
binding.matchTeamCard.setVisibility(View.GONE);
|
binding.matchTeamCard.setVisibility(View.GONE);
|
||||||
clear_fields();
|
clear_fields();
|
||||||
binding.matchTeamCard.setVisibility(View.VISIBLE);
|
binding.matchTeamCard.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
if(DataManager.match_values == null || DataManager.match_values.length == 0){
|
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.");
|
binding.MatchScoutArea.addView(
|
||||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
new TextViewBuilder(getContext(), "Failed to load fields.\nTry to either download or create match scouting fields.")
|
||||||
binding.MatchScoutArea.addView(tv);
|
.align_center()
|
||||||
|
.build());
|
||||||
|
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
binding.nextButton.setOnClickListener(v -> {
|
binding.bindicator.match_indicator_next_button.setOnClickListener(v -> {
|
||||||
if(edited) save();
|
if(edited) save();
|
||||||
SettingsManager.setMatchNum(cur_match_num+1);
|
SettingsManager.setMatchNum(cur_match_num+1);
|
||||||
cur_match_num += 1;
|
cur_match_num += 1;
|
||||||
@@ -74,21 +80,21 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(SettingsManager.getEnableQuickAlliancePosChange())
|
if(SettingsManager.getEnableQuickAlliancePosChange())
|
||||||
binding.fileIndicator.setOnClickListener(v -> {
|
binding.bindicator.setOnClickListener(v -> {
|
||||||
// if(e.getAction() != MotionEvent.ACTION_MOVE) return true;
|
// if(e.getAction() != MotionEvent.ACTION_MOVE) return true;
|
||||||
// System.out.println(e.getAxisValue(0));
|
// System.out.println(e.getAxisValue(0));
|
||||||
if(edited) save();
|
if(edited) save();
|
||||||
|
|
||||||
alliance_position = incrementMatchPos(alliance_position);
|
alliance_position = incrementMatchPos(alliance_position);
|
||||||
SettingsManager.setAllyPos(alliance_position);
|
SettingsManager.setAllyPos(alliance_position);
|
||||||
binding.alliancePosText.setText(alliance_position);
|
binding.bindicator.setAlliancePos(alliance_position);
|
||||||
|
|
||||||
update_match_num();
|
update_match_num();
|
||||||
update_scouting_data();
|
update_scouting_data();
|
||||||
// return true;
|
// return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
binding.backButton.setOnClickListener(v -> {
|
binding.bindicator.match_indicator_back_button.setOnClickListener(v -> {
|
||||||
if(edited) save();
|
if(edited) save();
|
||||||
SettingsManager.setMatchNum(cur_match_num-1);
|
SettingsManager.setMatchNum(cur_match_num-1);
|
||||||
cur_match_num -= 1;
|
cur_match_num -= 1;
|
||||||
@@ -150,7 +156,7 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
|
|
||||||
|
|
||||||
public void save(){
|
public void save(){
|
||||||
System.out.println("Saved!");
|
Log.i(this.getClass().toString(), "Saved!");
|
||||||
edited = false;
|
edited = false;
|
||||||
enableRescoutButton();
|
enableRescoutButton();
|
||||||
AlertManager.toast("Saved " + filename);
|
AlertManager.toast("Saved " + filename);
|
||||||
@@ -158,7 +164,7 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void set_indicator_color(int color){
|
public void set_indicator_color(int color){
|
||||||
binding.fileIndicator.setBackgroundColor(color);
|
binding.bindicator.setColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update_asm(){
|
public void update_asm(){
|
||||||
@@ -238,18 +244,18 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
|
|
||||||
edited = false;
|
edited = false;
|
||||||
|
|
||||||
binding.matchnum.setText(String.valueOf(cur_match_num+1));
|
binding.bindicator.setMatchNum(String.valueOf(cur_match_num+1));
|
||||||
|
|
||||||
if(cur_match_num <= 0){
|
if(cur_match_num <= 0){
|
||||||
binding.backButton.setVisibility(View.GONE);
|
binding.bindicator.match_indicator_back_button.setVisibility(View.GONE);
|
||||||
}else{
|
}else{
|
||||||
binding.backButton.setVisibility(View.VISIBLE);
|
binding.bindicator.match_indicator_back_button.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cur_match_num >= event.matches.size()-1){
|
if(cur_match_num >= event.matches.size()-1){
|
||||||
binding.nextButton.setVisibility(View.GONE);
|
binding.bindicator.match_indicator_next_button.setVisibility(View.GONE);
|
||||||
}else{
|
}else{
|
||||||
binding.nextButton.setVisibility(View.VISIBLE);
|
binding.bindicator.match_indicator_next_button.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +277,7 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.barTeamNum.setText(String.valueOf(team_num));
|
binding.bindicator.setTeamNum(String.valueOf(team_num));
|
||||||
|
|
||||||
frcTeam team = null;
|
frcTeam team = null;
|
||||||
for(int i=0; i < event.teams.size(); i++){
|
for(int i=0; i < event.teams.size(); i++){
|
||||||
@@ -345,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);
|
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues);
|
||||||
RawDataType[] types = psdr.data.array;
|
RawDataType[] types = psdr.data.array;
|
||||||
@@ -377,14 +383,14 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ScoutingDataWriter.save(DataManager.match_values.length-1, ScoutingDataWriter.checkAddName(fileUsernames, username), filename, types))
|
if(ScoutingDataWriter.save(DataManager.match_values.length-1, ScoutingDataWriter.checkAddName(fileUsernames, username), filename, types))
|
||||||
System.out.println("Saved!");
|
Log.i(getClass().toString(), "Saved!");
|
||||||
else
|
else
|
||||||
System.out.println("Error saving");
|
Log.i(getClass().toString(), "Error saving");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableRescoutButton(){
|
private void enableRescoutButton(){
|
||||||
set_indicator_color(rescout ? rescout_color : saved_color);
|
set_indicator_color(rescout ? rescout_color : saved_color);
|
||||||
binding.fileIndicator.setOnLongClickListener(v -> {
|
binding.bindicator.setOnLongClickListener(v -> {
|
||||||
rescout = !rescout;
|
rescout = !rescout;
|
||||||
if(rescout){
|
if(rescout){
|
||||||
set_indicator_color(rescout_color);
|
set_indicator_color(rescout_color);
|
||||||
@@ -401,6 +407,6 @@ public class MatchScoutingFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disableRescoutButton(){
|
private void disableRescoutButton(){
|
||||||
binding.fileIndicator.setOnLongClickListener(null);
|
binding.bindicator.setOnLongClickListener(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import static com.ridgebotics.ridgescout.utility.DataManager.pit_transferValues;
|
|||||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
import static com.ridgebotics.ridgescout.utility.DataManager.pit_values;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -19,8 +20,10 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.divider.MaterialDivider;
|
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.ui.views.ToggleTitleView;
|
||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentScoutingPitBinding;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||||
@@ -75,7 +78,6 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
|
|
||||||
String fileUsernames = "";
|
String fileUsernames = "";
|
||||||
ToggleTitleView[] titles;
|
ToggleTitleView[] titles;
|
||||||
|
|
||||||
AutoSaveManager asm = new AutoSaveManager(this::save, AUTO_SAVE_DELAY);
|
AutoSaveManager asm = new AutoSaveManager(this::save, AUTO_SAVE_DELAY);
|
||||||
|
|
||||||
ArrayList<RawDataType> rawDataTypes;
|
ArrayList<RawDataType> rawDataTypes;
|
||||||
@@ -91,14 +93,14 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ScoutingDataWriter.save(pit_values.length-1, ScoutingDataWriter.checkAddName(fileUsernames, username), filename, types)) {
|
if(ScoutingDataWriter.save(pit_values.length-1, ScoutingDataWriter.checkAddName(fileUsernames, username), filename, types)) {
|
||||||
System.out.println("Saved!");
|
Log.i(getClass().toString(), "Saved!");
|
||||||
AlertManager.toast("Saved " + filename);
|
Log.i(getClass().toString(), "Saved " + filename);
|
||||||
}else
|
}else
|
||||||
System.out.println("Error saving");
|
Log.i(getClass().toString(), "Error saving");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set_indicator_color(int color){
|
public void set_indicator_color(int color){
|
||||||
binding.pitFileIndicator.setBackgroundColor(color);
|
binding.pitIndicator.setColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update_asm(){
|
public void update_asm(){
|
||||||
@@ -113,10 +115,9 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
public void loadTeam(){
|
public void loadTeam(){
|
||||||
// clear_fields();
|
// clear_fields();
|
||||||
|
|
||||||
binding.pitFileIndicator.setVisibility(View.VISIBLE);
|
|
||||||
binding.pitsTeamCard.setVisibility(View.VISIBLE);
|
binding.pitsTeamCard.setVisibility(View.VISIBLE);
|
||||||
binding.pitBarTeamNum.setText(String.valueOf(team.teamNumber));
|
binding.pitIndicator.setTeamNum(team.teamNumber);
|
||||||
binding.pitUsername.setText(SettingsManager.getUsername());
|
binding.pitIndicator.setUsername(SettingsManager.getUsername());
|
||||||
binding.pitsTeamCard.fromTeam(team);
|
binding.pitsTeamCard.fromTeam(team);
|
||||||
|
|
||||||
filename = evcode + "-" + team.teamNumber + ".pitscoutdata";
|
filename = evcode + "-" + team.teamNumber + ".pitscoutdata";
|
||||||
@@ -145,7 +146,7 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.pitFileIndicator.bringToFront();
|
binding.pitIndicator.bringToFront();
|
||||||
|
|
||||||
asm.start();
|
asm.start();
|
||||||
|
|
||||||
@@ -153,7 +154,7 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
|
|
||||||
private void enableRescoutButton(){
|
private void enableRescoutButton(){
|
||||||
set_indicator_color(rescout ? rescout_color : saved_color);
|
set_indicator_color(rescout ? rescout_color : saved_color);
|
||||||
binding.pitFileIndicator.setOnLongClickListener(v -> {
|
binding.pitIndicator.setOnLongClickListener(v -> {
|
||||||
rescout = !rescout;
|
rescout = !rescout;
|
||||||
if(rescout){
|
if(rescout){
|
||||||
set_indicator_color(rescout_color);
|
set_indicator_color(rescout_color);
|
||||||
@@ -170,7 +171,7 @@ public class PitScoutingFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disableRescoutButton(){
|
private void disableRescoutButton(){
|
||||||
binding.pitFileIndicator.setOnLongClickListener(null);
|
binding.pitIndicator.setOnLongClickListener(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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);
|
ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||||
RawDataType[] types = psdr.data.array;
|
RawDataType[] types = psdr.data.array;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -22,10 +23,12 @@ import androidx.fragment.app.Fragment;
|
|||||||
|
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentScoutingBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentScoutingBinding;
|
||||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -88,7 +91,7 @@ public class ScoutingFragment extends Fragment {
|
|||||||
|
|
||||||
binding.textMatchAlliance.setVisibility(View.GONE);
|
binding.textMatchAlliance.setVisibility(View.GONE);
|
||||||
binding.textName.setVisibility(View.GONE);
|
binding.textName.setVisibility(View.GONE);
|
||||||
binding.textNextMatch.setVisibility(View.GONE);
|
binding.infoBox.setVisibility(View.GONE);
|
||||||
binding.textRescoutIndicator.setVisibility(View.GONE);
|
binding.textRescoutIndicator.setVisibility(View.GONE);
|
||||||
|
|
||||||
binding.matchScoutingButton.setEnabled(false);
|
binding.matchScoutingButton.setEnabled(false);
|
||||||
@@ -122,15 +125,7 @@ public class ScoutingFragment extends Fragment {
|
|||||||
findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_scouting_event);
|
findNavController(this).navigate(R.id.action_navigation_scouting_to_navigation_scouting_event);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateDashboard();
|
||||||
binding.textName.setText("Welcome, " + SettingsManager.getUsername() + "!");
|
|
||||||
|
|
||||||
int matchNum = SettingsManager.getMatchNum();
|
|
||||||
int nextMatch = event.getNextTeamMatch(SettingsManager.getTeamNum(), matchNum).matchIndex;
|
|
||||||
|
|
||||||
binding.textNextMatch.setText("Our next match: Match " + nextMatch);
|
|
||||||
binding.textMatchAlliance.setText("Match: " + (matchNum+1) + ", " + SettingsManager.getAllyPos());
|
|
||||||
binding.textRescoutIndicator.setText("Things to rescout: " + DataManager.rescout_list.size());
|
|
||||||
|
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
@@ -159,4 +154,31 @@ 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());
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,9 +18,14 @@ import com.ridgebotics.ridgescout.types.input.NumberType;
|
|||||||
import com.ridgebotics.ridgescout.types.input.SliderType;
|
import com.ridgebotics.ridgescout.types.input.SliderType;
|
||||||
import com.ridgebotics.ridgescout.types.input.TallyType;
|
import com.ridgebotics.ridgescout.types.input.TallyType;
|
||||||
import com.ridgebotics.ridgescout.types.input.TextType;
|
import com.ridgebotics.ridgescout.types.input.TextType;
|
||||||
|
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
// Class to help with fields editor fragment, containing the defaults for each field.
|
// Class to help with fields editor fragment, containing the defaults for each field.
|
||||||
@@ -29,7 +34,8 @@ public class FieldEditorHelper {
|
|||||||
paramNumber,
|
paramNumber,
|
||||||
paramString,
|
paramString,
|
||||||
paramStringArray,
|
paramStringArray,
|
||||||
paramNumberArray
|
paramNumberArray,
|
||||||
|
paramDropdown
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class parameterType {
|
public static class parameterType {
|
||||||
@@ -64,6 +70,17 @@ public class FieldEditorHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class paramDropdown extends parameterType{
|
||||||
|
public List<String> options;
|
||||||
|
public int val;
|
||||||
|
public paramDropdown(String name, List<String> options, int val){
|
||||||
|
this.name = name + " (Dropdown)";
|
||||||
|
this.options = options;
|
||||||
|
this.val = val;
|
||||||
|
this.id = parameterTypeEnum.paramDropdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public static class paramNumberArray extends parameterType{
|
// public static class paramNumberArray extends parameterType{
|
||||||
// public int[] val;
|
// public int[] val;
|
||||||
// public paramNumberArray(String name, int[] val){
|
// public paramNumberArray(String name, int[] val){
|
||||||
@@ -166,9 +183,16 @@ public class FieldEditorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static parameterType[] getFieldPosParam(FieldposType s){
|
private static parameterType[] getFieldPosParam(FieldposType s){
|
||||||
|
FieldposType.FieldImage[] f_images = FieldposType.FieldImage.values();
|
||||||
|
List<String> images = new ArrayList<>();
|
||||||
|
for (FieldposType.FieldImage fimage: f_images) {
|
||||||
|
images.add(fimage.toString());
|
||||||
|
}
|
||||||
|
|
||||||
return new parameterType[]{
|
return new parameterType[]{
|
||||||
new paramString("Name", s.name),
|
new paramString("Name", s.name),
|
||||||
new paramString("Description", s.description),
|
new paramString("Description", s.description),
|
||||||
|
new paramDropdown("Field Image", images, 0),
|
||||||
new paramNumber("Default X", ((int[]) s.default_value)[0]),
|
new paramNumber("Default X", ((int[]) s.default_value)[0]),
|
||||||
new paramNumber("Default Y", ((int[]) s.default_value)[1])
|
new paramNumber("Default Y", ((int[]) s.default_value)[1])
|
||||||
};
|
};
|
||||||
@@ -218,9 +242,10 @@ public class FieldEditorHelper {
|
|||||||
public static void setFieldPosParam(FieldposType s, parameterType[] types){
|
public static void setFieldPosParam(FieldposType s, parameterType[] types){
|
||||||
s.name = ((paramString) types[0]).val;
|
s.name = ((paramString) types[0]).val;
|
||||||
s.description = ((paramString) types[1]).val;
|
s.description = ((paramString) types[1]).val;
|
||||||
|
s.fieldImage = FieldposType.FieldImage.from_index(((paramDropdown) types[2]).val);
|
||||||
s.default_value = new int[]{
|
s.default_value = new int[]{
|
||||||
((paramNumber) types[2]).val,
|
((paramNumber) types[3]).val,
|
||||||
((paramNumber) types[3]).val
|
((paramNumber) types[4]).val
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,6 +331,24 @@ public class FieldEditorHelper {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static View createDropdown(Context c, String name, List<String> options, int value){
|
||||||
|
CustomSpinnerView spinner = new CustomSpinnerView(c);
|
||||||
|
spinner.setTitle(name);
|
||||||
|
spinner.setOptions(options, value);
|
||||||
|
spinner.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
// EditText text = new EditText(c);
|
||||||
|
// text.setText(String.join("\n", value));
|
||||||
|
// text.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
// ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
// ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
// ));
|
||||||
|
return spinner;
|
||||||
|
}
|
||||||
|
|
||||||
private static View createEdit(Context c, parameterType t){
|
private static View createEdit(Context c, parameterType t){
|
||||||
switch (t.id){
|
switch (t.id){
|
||||||
case paramNumber:
|
case paramNumber:
|
||||||
@@ -314,6 +357,8 @@ public class FieldEditorHelper {
|
|||||||
return createStringEdit(c, ((paramString) t).val);
|
return createStringEdit(c, ((paramString) t).val);
|
||||||
case paramStringArray:
|
case paramStringArray:
|
||||||
return createStringArrayEdit(c, ((paramStringArray) t).val);
|
return createStringArrayEdit(c, ((paramStringArray) t).val);
|
||||||
|
case paramDropdown:
|
||||||
|
return createDropdown(c, t.name, ((paramDropdown) t).options, ((paramDropdown) t).val);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -321,22 +366,27 @@ public class FieldEditorHelper {
|
|||||||
|
|
||||||
private static boolean readEdit(View v, parameterType t){
|
private static boolean readEdit(View v, parameterType t){
|
||||||
try{
|
try{
|
||||||
String val;
|
// String val;
|
||||||
switch (t.id) {
|
switch (t.id) {
|
||||||
case paramNumber:
|
case paramNumber:
|
||||||
val = ((EditText) v).getText().toString();
|
String val1 = ((EditText) v).getText().toString();
|
||||||
if(val.isEmpty() || val.isBlank()) return false;
|
if(val1.isEmpty() || val1.isBlank()) return false;
|
||||||
((paramNumber) t).val = Integer.parseInt(val);
|
((paramNumber) t).val = Integer.parseInt(val1);
|
||||||
break;
|
break;
|
||||||
case paramString:
|
case paramString:
|
||||||
val = ((EditText) v).getText().toString();
|
String val2 = ((EditText) v).getText().toString();
|
||||||
//if(val.isEmpty() || val.isBlank()) return false;
|
//if(val.isEmpty() || val.isBlank()) return false;
|
||||||
((paramString) t).val = val;
|
((paramString) t).val = val2;
|
||||||
break;
|
break;
|
||||||
case paramStringArray:
|
case paramStringArray:
|
||||||
val = ((EditText) v).getText().toString();
|
String val3 = ((EditText) v).getText().toString();
|
||||||
if(val.isEmpty() || val.isBlank()) return false;
|
if(val3.isEmpty() || val3.isBlank()) return false;
|
||||||
((paramStringArray) t).val = val.split("\n");
|
((paramStringArray) t).val = val3.split("\n");
|
||||||
|
break;
|
||||||
|
case paramDropdown:
|
||||||
|
int val4 = ((CustomSpinnerView) v).getIndex();
|
||||||
|
// if(val.isEmpty() || val.isBlank()) return false;
|
||||||
|
((paramDropdown) t).val = val4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -397,11 +447,11 @@ public class FieldEditorHelper {
|
|||||||
this.t = t;
|
this.t = t;
|
||||||
views = new View[types.length];
|
views = new View[types.length];
|
||||||
for(int i = 0; i < types.length; i++){
|
for(int i = 0; i < types.length; i++){
|
||||||
TextView tv = new TextView(c);
|
|
||||||
tv.setText(types[i].name);
|
parentView.addView(new TextViewBuilder(c, types[i].name)
|
||||||
tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
.align_center()
|
||||||
tv.setTextSize(20);
|
.size(20)
|
||||||
parentView.addView(tv);
|
.build());
|
||||||
|
|
||||||
views[i] = createEdit(c, types[i]);
|
views[i] = createEdit(c, types[i]);
|
||||||
parentView.addView(views[i]);
|
parentView.addView(views[i]);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.annotation.SuppressLint;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -20,6 +21,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.ridgebotics.ridgescout.MainActivity;
|
import com.ridgebotics.ridgescout.MainActivity;
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentSettingsFieldsBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentSettingsFieldsBinding;
|
||||||
@@ -28,6 +30,7 @@ import com.ridgebotics.ridgescout.types.input.FieldType;
|
|||||||
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
||||||
import com.ridgebotics.ridgescout.ui.views.FieldDisplay;
|
import com.ridgebotics.ridgescout.ui.views.FieldDisplay;
|
||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -194,10 +197,9 @@ public class FieldsFragment extends Fragment {
|
|||||||
|
|
||||||
sv.addView(table);
|
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);
|
FieldEditorHelper f = new FieldEditorHelper(getContext(), field, table);
|
||||||
|
|
||||||
@@ -215,7 +217,7 @@ public class FieldsFragment extends Fragment {
|
|||||||
AlertDialog dialog = alert.create();
|
AlertDialog dialog = alert.create();
|
||||||
dialog.show();
|
dialog.show();
|
||||||
|
|
||||||
Button deleteButton = new Button(getContext());
|
MaterialButton deleteButton = new MaterialButton(getContext());
|
||||||
deleteButton.setText("DELETE");
|
deleteButton.setText("DELETE");
|
||||||
deleteButton.setOnClickListener(l -> {
|
deleteButton.setOnClickListener(l -> {
|
||||||
AlertDialog.Builder alert2 = new AlertDialog.Builder(getContext());
|
AlertDialog.Builder alert2 = new AlertDialog.Builder(getContext());
|
||||||
@@ -270,7 +272,7 @@ public class FieldsFragment extends Fragment {
|
|||||||
|
|
||||||
System.arraycopy(currentValues, 0, newValues, 0, currentValues.length);
|
System.arraycopy(currentValues, 0, newValues, 0, currentValues.length);
|
||||||
|
|
||||||
System.out.println("Length: " + values.size());
|
Log.i(getClass().toString(), "Length: " + values.size());
|
||||||
|
|
||||||
newValues[currentValues.length] = new FieldType[values.size()];
|
newValues[currentValues.length] = new FieldType[values.size()];
|
||||||
for(int i = 0; i < values.size(); i++) {
|
for(int i = 0; i < values.size(); i++) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ridgebotics.ridgescout.ui.settings;
|
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;
|
import static androidx.navigation.fragment.FragmentKt.findNavController;
|
||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.AllyPosKey;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.AllyPosKey;
|
||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.CustomEventsKey;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.CustomEventsKey;
|
||||||
@@ -13,11 +14,15 @@ import static com.ridgebotics.ridgescout.utility.SettingsManager.UnameKey;
|
|||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.WifiModeKey;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.WifiModeKey;
|
||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.YearNumKey;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.YearNumKey;
|
||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.defaults;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.defaults;
|
||||||
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.getEVCode;
|
||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.getEditor;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.getEditor;
|
||||||
import static com.ridgebotics.ridgescout.utility.SettingsManager.prefs;
|
import static com.ridgebotics.ridgescout.utility.SettingsManager.prefs;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
@@ -26,7 +31,6 @@ import android.view.Gravity;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
@@ -36,7 +40,9 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||||
|
import com.google.android.material.divider.MaterialDivider;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
@@ -44,8 +50,11 @@ import com.ridgebotics.ridgescout.databinding.FragmentSettingsBinding;
|
|||||||
import com.ridgebotics.ridgescout.scoutingData.Fields;
|
import com.ridgebotics.ridgescout.scoutingData.Fields;
|
||||||
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView;
|
||||||
import com.ridgebotics.ridgescout.ui.views.TallyCounterView;
|
import com.ridgebotics.ridgescout.ui.views.TallyCounterView;
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
|
import com.ridgebotics.ridgescout.utility.ToDelete;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -64,20 +73,6 @@ public class SettingsFragment extends Fragment {
|
|||||||
|
|
||||||
reloadSettings();
|
reloadSettings();
|
||||||
|
|
||||||
binding.fieldsButton.setOnClickListener(v -> {
|
|
||||||
binding.fieldsButton.setEnabled(false);
|
|
||||||
binding.fieldsButtons.setVisibility(VISIBLE);
|
|
||||||
});
|
|
||||||
|
|
||||||
binding.fieldsMatchesButton.setOnClickListener(v -> {
|
|
||||||
FieldsFragment.set_filename(Fields.matchFieldsFilename);
|
|
||||||
findNavController(this).navigate(R.id.action_navigation_settings_to_navigation_data_fields);
|
|
||||||
});
|
|
||||||
|
|
||||||
binding.fieldsPitsButton.setOnClickListener(v -> {
|
|
||||||
FieldsFragment.set_filename(Fields.pitsFieldsFilename);
|
|
||||||
findNavController(this).navigate(R.id.action_navigation_settings_to_navigation_data_fields);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
@@ -90,25 +85,73 @@ public class SettingsFragment extends Fragment {
|
|||||||
SettingsManager manager = new SettingsManager(getContext());
|
SettingsManager manager = new SettingsManager(getContext());
|
||||||
|
|
||||||
|
|
||||||
|
ButtonSettingsItem appInfoButton = new ButtonSettingsItem();
|
||||||
|
appInfoButton.addButton("App info", v -> showAppInfo());
|
||||||
|
manager.addItem(appInfoButton);
|
||||||
|
|
||||||
|
|
||||||
|
ButtonSettingsItem corruptButton = new ButtonSettingsItem();
|
||||||
|
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"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ButtonSettingsItem fieldsButtons = new ButtonSettingsItem();
|
||||||
|
fieldsButtons.addButton("Edit pit fields", v -> {
|
||||||
|
FieldsFragment.set_filename(Fields.pitsFieldsFilename);
|
||||||
|
findNavController(this).navigate(R.id.action_navigation_settings_to_navigation_data_fields);
|
||||||
|
});
|
||||||
|
fieldsButtons.addButton("Edit match fields", v -> {
|
||||||
|
FieldsFragment.set_filename(Fields.matchFieldsFilename);
|
||||||
|
findNavController(this).navigate(R.id.action_navigation_settings_to_navigation_data_fields);
|
||||||
|
});
|
||||||
|
manager.addItem(fieldsButtons);
|
||||||
|
|
||||||
|
ButtonSettingsItem noticeButton = new ButtonSettingsItem();
|
||||||
|
noticeButton.addButton("Edit scout notice", v->editNotice());
|
||||||
|
noticeButton.setEnabled(!getEVCode().equals("unset"));
|
||||||
|
manager.addItem(noticeButton);
|
||||||
|
|
||||||
|
|
||||||
manager.addItem(new CheckboxSettingsItem(CustomEventsKey, "Custom Events"));
|
manager.addItem(new CheckboxSettingsItem(CustomEventsKey, "Custom Events"));
|
||||||
|
|
||||||
StringSettingsItem FTPServer = new StringSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPServer, "FTP Server (Sync)");
|
CheckboxSettingsItem FTPSendMetaFiles = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPSendMetaFiles, "[⚠] Send meta files");
|
||||||
manager.addItem(FTPServer);
|
|
||||||
CheckboxSettingsItem FTPSendMetaFiles = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPSendMetaFiles, "Sync meta files");
|
|
||||||
manager.addItem(FTPSendMetaFiles);
|
manager.addItem(FTPSendMetaFiles);
|
||||||
CheckboxSettingsItem FTPEnabled = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPEnabled, "FTP Enabled", FTPServer, FTPSendMetaFiles);
|
|
||||||
|
manager.addItem(new HeaderSettingsItem("Admin"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
StringSettingsItem FTPKey = new StringSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPKey, "Sync Key");
|
||||||
|
manager.addItem(FTPKey);
|
||||||
|
StringSettingsItem FTPServer = new StringSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPServer, "Sync Server (Sync)");
|
||||||
|
manager.addItem(FTPServer);
|
||||||
|
CheckboxSettingsItem FTPEnabled = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPEnabled, "Sync Enabled", FTPServer, FTPKey, FTPSendMetaFiles);
|
||||||
manager.addItem(FTPEnabled);
|
manager.addItem(FTPEnabled);
|
||||||
|
|
||||||
manager.addItem(new CheckboxSettingsItem(WifiModeKey, "Wifi Mode", FTPEnabled));
|
manager.addItem(new CheckboxSettingsItem(WifiModeKey, "Wifi Mode", FTPEnabled));
|
||||||
manager.addItem(new CheckboxSettingsItem(EnableQuickAllianceChangeKey, "Enable quick alliance swap", null));
|
|
||||||
|
|
||||||
manager.addItem(new DropdownSettingsItem(FieldImageKey, "Field Image", new String[]{
|
|
||||||
"2025",
|
|
||||||
"2025 (Flipped)"
|
|
||||||
}));
|
|
||||||
|
|
||||||
manager.addItem(new NumberSettingsItem(YearNumKey, "Year", 0, 9999));
|
manager.addItem(new NumberSettingsItem(YearNumKey, "Year", 0, 9999));
|
||||||
|
|
||||||
|
manager.addItem(new HeaderSettingsItem("Connection"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
manager.addItem(new CheckboxSettingsItem(EnableQuickAllianceChangeKey, "Enable quick alliance swap", null));
|
||||||
|
manager.addItem(new CheckboxSettingsItem(FieldImageKey, "Field Image", null));
|
||||||
|
|
||||||
manager.addItem(new DropdownSettingsItem(AllyPosKey, "Alliance Pos", alliance_pos_list));
|
manager.addItem(new DropdownSettingsItem(AllyPosKey, "Alliance Pos", alliance_pos_list));
|
||||||
|
|
||||||
@@ -131,16 +174,48 @@ public class SettingsFragment extends Fragment {
|
|||||||
|
|
||||||
manager.addItem(new StringSettingsItem(UnameKey, "Username"));
|
manager.addItem(new StringSettingsItem(UnameKey, "Username"));
|
||||||
manager.addItem(new NumberSettingsItem(TeamNumKey, "Team Number", 0, 99999));
|
manager.addItem(new NumberSettingsItem(TeamNumKey, "Team Number", 0, 99999));
|
||||||
|
manager.addItem(new HeaderSettingsItem("Scouting"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
binding.SettingsTable.removeAllViews();
|
binding.SettingsTable.removeAllViews();
|
||||||
|
|
||||||
manager.getView(binding.SettingsTable);
|
manager.getView(binding.SettingsTable);
|
||||||
|
|
||||||
if(!DataManager.getevcode().equals("unset")){
|
|
||||||
Button editNoticeButton = new Button(getContext());
|
// Add "Edit scout notice" button to the bottom of the page=
|
||||||
editNoticeButton.setText("Edit Scout Notice");
|
|
||||||
binding.SettingsTable.addView(editNoticeButton);
|
|
||||||
editNoticeButton.setOnClickListener(v->editNotice());
|
// Add "Field edit" buttons to the bottom of the page
|
||||||
}
|
// LinearLayout fieldButtons = new LinearLayout(getContext());
|
||||||
|
// fieldButtons.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
// LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
// LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
// ));
|
||||||
|
// fieldButtons.setOrientation(HORIZONTAL);
|
||||||
|
//
|
||||||
|
// Button editMatchFieldsButton = new Button(getContext());
|
||||||
|
// editMatchFieldsButton.setText("Edit Match Fields");
|
||||||
|
// editMatchFieldsButton.setOnClickListener(v -> {
|
||||||
|
// FieldsFragment.set_filename(Fields.matchFieldsFilename);
|
||||||
|
// findNavController(this).navigate(R.id.action_navigation_settings_to_navigation_data_fields);
|
||||||
|
// });
|
||||||
|
// fieldButtons.addView(editMatchFieldsButton);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Button editPitsFieldsButton = new Button(getContext());
|
||||||
|
// editPitsFieldsButton.setText("Edit pits Fields");
|
||||||
|
// editPitsFieldsButton.setOnClickListener(v -> {
|
||||||
|
// FieldsFragment.set_filename(Fields.pitsFieldsFilename);
|
||||||
|
// findNavController(this).navigate(R.id.action_navigation_settings_to_navigation_data_fields);
|
||||||
|
// });
|
||||||
|
// fieldButtons.addView(editPitsFieldsButton);
|
||||||
|
|
||||||
|
|
||||||
|
// binding.SettingsTable.addView(fieldButtons);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +250,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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -281,9 +391,8 @@ public class SettingsFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View createView(Context context) {
|
public View createView(Context context) {
|
||||||
TextView titleView = new TextView(context);
|
TextView titleView = new TextViewBuilder(context, getTitle())
|
||||||
titleView.setText(getTitle());
|
.sub1().build();
|
||||||
titleView.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1);
|
|
||||||
|
|
||||||
TextInputLayout textInputLayout = new TextInputLayout(context);
|
TextInputLayout textInputLayout = new TextInputLayout(context);
|
||||||
editText = new TextInputEditText(context);
|
editText = new TextInputEditText(context);
|
||||||
@@ -344,7 +453,7 @@ public class SettingsFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public View createView(Context context) {
|
public View createView(Context context) {
|
||||||
LinearLayout ll = new LinearLayout(getContext());
|
LinearLayout ll = new LinearLayout(getContext());
|
||||||
ll.setOrientation(LinearLayout.VERTICAL);
|
ll.setOrientation(VERTICAL);
|
||||||
|
|
||||||
tally = new TallyCounterView(getContext());
|
tally = new TallyCounterView(getContext());
|
||||||
|
|
||||||
@@ -363,11 +472,10 @@ public class SettingsFragment extends Fragment {
|
|||||||
});
|
});
|
||||||
tally.setEnabled(enabled);
|
tally.setEnabled(enabled);
|
||||||
|
|
||||||
TextView tv = new TextView(getContext());
|
|
||||||
tv.setText(getTitle());
|
ll.addView(new TextViewBuilder(getContext(), getTitle())
|
||||||
tv.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline6);
|
.h6()
|
||||||
tv.setGravity(Gravity.CENTER);
|
.build());
|
||||||
ll.addView(tv);
|
|
||||||
|
|
||||||
ll.addView(tally);
|
ll.addView(tally);
|
||||||
|
|
||||||
@@ -472,6 +580,93 @@ public class SettingsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class HeaderSettingsItem extends SettingsItem<Void> {
|
||||||
|
String title;
|
||||||
|
|
||||||
|
public HeaderSettingsItem(String title) {
|
||||||
|
super("", title, null);
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
LinearLayout ll = new LinearLayout(context);
|
||||||
|
ll.setOrientation(VERTICAL);
|
||||||
|
ll.setPadding(0, 20,0,0);
|
||||||
|
|
||||||
|
ll.addView(new TextViewBuilder(context, title)
|
||||||
|
.h4()
|
||||||
|
.build());
|
||||||
|
|
||||||
|
ll.addView(new MaterialDivider(context));
|
||||||
|
|
||||||
|
return ll;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void getValue() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ButtonSettingsItem extends SettingsItem<Void> {
|
||||||
|
List<MaterialButton> buttons = new ArrayList<>();
|
||||||
|
List<String> titles = new ArrayList<>();
|
||||||
|
List<View.OnClickListener> callbacks = new ArrayList<>();
|
||||||
|
|
||||||
|
boolean enabled = true;
|
||||||
|
|
||||||
|
public ButtonSettingsItem() {
|
||||||
|
super("", "", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled){
|
||||||
|
this.enabled = enabled;
|
||||||
|
for(int i = 0; i < buttons.size(); i++){
|
||||||
|
buttons.get(i).setEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addButton(String text, View.OnClickListener onClickListener) {
|
||||||
|
titles.add(text);
|
||||||
|
callbacks.add(onClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
LinearLayout ll = new LinearLayout(context);
|
||||||
|
ll.setOrientation(HORIZONTAL);
|
||||||
|
|
||||||
|
for(int i = 0; i < titles.size(); i++){
|
||||||
|
MaterialButton button = new MaterialButton(context);
|
||||||
|
button.setText(titles.get(i));
|
||||||
|
button.setOnClickListener(callbacks.get(i));
|
||||||
|
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f);
|
||||||
|
layoutParams.setMargins(3, 0, 3, 0);
|
||||||
|
// layoutParams.weight
|
||||||
|
button.setLayoutParams(layoutParams);
|
||||||
|
button.setEnabled(enabled);
|
||||||
|
// button.weight
|
||||||
|
buttons.add(button);
|
||||||
|
|
||||||
|
ll.addView(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ll;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void getValue() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class SettingsManager {
|
public class SettingsManager {
|
||||||
private Context context;
|
private Context context;
|
||||||
private HashMap<String, Object> settings;
|
private HashMap<String, Object> settings;
|
||||||
@@ -494,7 +689,7 @@ public class SettingsFragment extends Fragment {
|
|||||||
items.add(item);
|
items.add(item);
|
||||||
|
|
||||||
LinearLayout itemContainer = new LinearLayout(context);
|
LinearLayout itemContainer = new LinearLayout(context);
|
||||||
itemContainer.setOrientation(LinearLayout.VERTICAL);
|
itemContainer.setOrientation(VERTICAL);
|
||||||
itemContainer.setPadding(32, 0, 32, 8);
|
itemContainer.setPadding(32, 0, 32, 8);
|
||||||
|
|
||||||
View view = item.createView(context);
|
View view = item.createView(context);
|
||||||
|
|||||||
@@ -1,269 +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 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;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
System.out.println("Uploaded" + localFile.getName());
|
|
||||||
|
|
||||||
setLocalFileTimestamp(localFile, curSyncTime);
|
|
||||||
remoteTimestamps.put(localFile.getName(), curSyncTime);
|
|
||||||
upCount++;
|
|
||||||
}else{
|
|
||||||
System.out.println("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);
|
|
||||||
|
|
||||||
System.out.println("Downloaded " + localFile.getName());
|
|
||||||
|
|
||||||
if(!localFile.exists()) System.out.println("Not exist");
|
|
||||||
else if(after(remoteTimestamp, localTimeStamp)) System.out.println("Before: " + (localTimeStamp.getTime()-remoteTimestamp.getTime()));
|
|
||||||
|
|
||||||
// Date d = getUtcTimestamp(remoteFile);
|
|
||||||
setLocalFileTimestamp(localFile, remoteTimestamps.get(localFile.getName()));
|
|
||||||
// remoteTimestamps.put(remoteFile, curSyncTime);
|
|
||||||
downCount++;
|
|
||||||
}else{
|
|
||||||
System.out.println("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.ByteBuilder;
|
||||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -49,7 +50,10 @@ public class FileSelectorFragment extends Fragment {
|
|||||||
meta_string_array = new String[]{
|
meta_string_array = new String[]{
|
||||||
"matches.fields",
|
"matches.fields",
|
||||||
"pits.fields",
|
"pits.fields",
|
||||||
evcode+".eventdata"
|
evcode+".eventdata",
|
||||||
|
evcode+".rescout",
|
||||||
|
evcode+".scoutnotice",
|
||||||
|
"todelete.colabarray",
|
||||||
};
|
};
|
||||||
|
|
||||||
String[] files = FileEditor.getEventFiles(evcode);
|
String[] files = FileEditor.getEventFiles(evcode);
|
||||||
@@ -74,10 +78,12 @@ public class FileSelectorFragment extends Fragment {
|
|||||||
checkBox.setChecked(true);
|
checkBox.setChecked(true);
|
||||||
tr.addView(checkBox);
|
tr.addView(checkBox);
|
||||||
|
|
||||||
TextView tv = new TextView(getContext());
|
// Filename
|
||||||
tv.setText(String.valueOf(files[i]));
|
tr.addView(
|
||||||
tv.setTextSize(20);
|
new TextViewBuilder(getContext(), files[i])
|
||||||
tr.addView(tv);
|
.size(20)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
final int fi = i;
|
final int fi = i;
|
||||||
tr.setOnClickListener(view -> {
|
tr.setOnClickListener(view -> {
|
||||||
|
|||||||
@@ -0,0 +1,385 @@
|
|||||||
|
package com.ridgebotics.ridgescout.ui.transfer;
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
// Class to synchronise data over HTTP.
|
||||||
|
public class HttpSync extends Thread {
|
||||||
|
public static final String timestampsFilename = "timestamps";
|
||||||
|
|
||||||
|
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();
|
||||||
|
HttpSync sync = new HttpSync();
|
||||||
|
|
||||||
|
sync.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int upCount = 0;
|
||||||
|
private int downCount = 0;
|
||||||
|
|
||||||
|
private class TransferFile {
|
||||||
|
public String filename;
|
||||||
|
public Date updated;
|
||||||
|
public String checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TransferFile> localFiles = new ArrayList<>();
|
||||||
|
private List<TransferFile> remoteFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void await() {
|
||||||
|
while(!runningRequest.get()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AtomicBoolean runningRequest = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
setUpdateIndicator("Getting Metadata...");
|
||||||
|
|
||||||
|
// Load metadata from server
|
||||||
|
getRemoteFileMetadata(serverIP, serverKey);
|
||||||
|
|
||||||
|
if(!isRunning){
|
||||||
|
setUpdateIndicator("Error Connecting");
|
||||||
|
onResult.onResult(true, upCount, downCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getLocalFileMetadata();
|
||||||
|
|
||||||
|
localFiles.removeIf(localFile -> removeFiles.contains(localFile.filename+","+localFile.checksum));
|
||||||
|
remoteFiles.removeIf(remoteFile -> removeFiles.contains(remoteFile.filename+","+remoteFile.checksum));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Wait for metadata request to finish
|
||||||
|
|
||||||
|
setUpdateIndicator("Uploading 0%");
|
||||||
|
|
||||||
|
for(int i = 0; i < localFiles.size(); i++){
|
||||||
|
TransferFile localFile = localFiles.get(i);
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Log.d(getClass().toString(), "LocalFile: " + localFile.filename + ", " + localFile.checksum + ", " + localFile.updated + ": Not uploaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpdateIndicator("Uploading " + (Math.floor((double) (i * 1000) / localFiles.size()) / 10) + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpdateIndicator("Downloading 0%");
|
||||||
|
|
||||||
|
for(int i = 0; i < remoteFiles.size(); i++){
|
||||||
|
TransferFile remoteFile = remoteFiles.get(i);
|
||||||
|
|
||||||
|
TransferFile localFile = findInFileArray(localFiles, remoteFile.filename);
|
||||||
|
|
||||||
|
boolean shouldUpload;
|
||||||
|
|
||||||
|
// If there is no file on the sever, upload.
|
||||||
|
if(localFile == null) {
|
||||||
|
shouldUpload = true;
|
||||||
|
} 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 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 datesEqual = !localFile.updated.equals(remoteFile.updated);
|
||||||
|
|
||||||
|
shouldUpload = (!checksumsEqual && (after) && !datesEqual);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shouldUpload) {
|
||||||
|
downloadFile(remoteFile, serverIP);
|
||||||
|
// await();
|
||||||
|
Log.d(getClass().toString(), "RemoteFile: " + remoteFile.filename + ", " + remoteFile.checksum + ", " + remoteFile.updated + ": Downloaded");
|
||||||
|
downCount++;
|
||||||
|
} else {
|
||||||
|
Log.d(getClass().toString(), "RemoteFile: " + remoteFile.filename + ", " + remoteFile.checksum + ", " + remoteFile.updated + ": Not downloaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setUpdateIndicator("Downloading " + (Math.floor((double) (i * 1000) / remoteFiles.size()) / 10) + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove files marked for deletion
|
||||||
|
ToDelete.deleteFiles();
|
||||||
|
|
||||||
|
setUpdateIndicator("Finished, " + upCount + " Up, " + downCount + " Down");
|
||||||
|
|
||||||
|
|
||||||
|
onResult.onResult(false, upCount, downCount);
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find file based off of filename
|
||||||
|
private TransferFile findInFileArray(List<TransferFile> files, String filename){
|
||||||
|
for(TransferFile file : files) {
|
||||||
|
if(file.filename.equals(filename))
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get teh last modified date of a file
|
||||||
|
private Date getLocalFileUtcTimestamp(File file) {
|
||||||
|
return new Date(file.lastModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the local metadata of files
|
||||||
|
private void getLocalFileMetadata() {
|
||||||
|
File localDir = new File(baseDir);
|
||||||
|
File[] localFileNames = localDir.listFiles();
|
||||||
|
|
||||||
|
assert localFileNames != null;
|
||||||
|
for (int i = 0; i < localFileNames.length; i++) {
|
||||||
|
File file = localFileNames[i];
|
||||||
|
|
||||||
|
if(file.isDirectory()) continue;
|
||||||
|
// Remove timestamts file
|
||||||
|
if(file.getName().equals(timestampsFilename)) continue;
|
||||||
|
|
||||||
|
TransferFile tf = new TransferFile();
|
||||||
|
tf.filename = file.getName();
|
||||||
|
tf.updated = getLocalFileUtcTimestamp(file);
|
||||||
|
try {
|
||||||
|
tf.checksum = FileEditor.getSHA256Hash(file.getName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
AlertManager.error("Failed to get hash of: " + file.getName(), e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
localFiles.add(tf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send request to server and retrieve metadata
|
||||||
|
private void getRemoteFileMetadata(String serverURL, String serverKey) {
|
||||||
|
final RequestTask rq = new RequestTask();
|
||||||
|
runningRequest.set(false);
|
||||||
|
rq.onResult(metadata -> {
|
||||||
|
try {
|
||||||
|
JSONObject j = new JSONObject(metadata);
|
||||||
|
for (Iterator<String> it = j.keys(); it.hasNext(); ) {
|
||||||
|
String key = it.next();
|
||||||
|
|
||||||
|
JSONObject obj = j.getJSONObject(key);
|
||||||
|
|
||||||
|
TransferFile tf = new TransferFile();
|
||||||
|
tf.filename = key;
|
||||||
|
tf.updated = new Date(Long.parseLong(obj.getString("modified")));
|
||||||
|
tf.checksum = obj.getString("sha256");
|
||||||
|
|
||||||
|
remoteFiles.add(tf);
|
||||||
|
}
|
||||||
|
}catch(JSONException | NullPointerException e ) {
|
||||||
|
AlertManager.error(e);
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
runningRequest.set(true);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
rq.execute((serverURL + "/api/metadata"), "api_key: " + serverKey);
|
||||||
|
await();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create HTTP request to upload file
|
||||||
|
void uploadFile(TransferFile tf, String serverURL, String apiKey, boolean special) {
|
||||||
|
runningRequest.set(false);
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
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, (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();
|
||||||
|
|
||||||
|
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 static com.ridgebotics.ridgescout.utility.FileEditor.TBAHeader;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -22,6 +26,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferTbaBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentTransferTbaBinding;
|
||||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||||
@@ -33,6 +38,7 @@ import com.ridgebotics.ridgescout.utility.JSONUtil;
|
|||||||
import com.ridgebotics.ridgescout.utility.RequestTask;
|
import com.ridgebotics.ridgescout.utility.RequestTask;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -40,6 +46,7 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
// Class to download data from a specific event and encode it.
|
// Class to download data from a specific event and encode it.
|
||||||
public class TBAEventFragment extends Fragment {
|
public class TBAEventFragment extends Fragment {
|
||||||
@@ -49,8 +56,6 @@ public class TBAEventFragment extends Fragment {
|
|||||||
|
|
||||||
private final int year = SettingsManager.getYearNum();
|
private final int year = SettingsManager.getYearNum();
|
||||||
|
|
||||||
private ProgressDialog loadingDialog;
|
|
||||||
|
|
||||||
private static JSONObject eventData = null;
|
private static JSONObject eventData = null;
|
||||||
public static void setEventData(JSONObject j){
|
public static void setEventData(JSONObject j){
|
||||||
eventData = j;
|
eventData = j;
|
||||||
@@ -72,27 +77,18 @@ public class TBAEventFragment extends Fragment {
|
|||||||
|
|
||||||
Table = binding.matchTable;
|
Table = binding.matchTable;
|
||||||
|
|
||||||
Table.setStretchAllColumns(true);
|
AlertManager.startLoading("Loading Teams and Matches...");
|
||||||
|
|
||||||
startLoading("Loading Teams and Matches...");
|
// Table.removeAllViews();
|
||||||
Table.removeAllViews();
|
|
||||||
Table.setStretchAllColumns(true);
|
Table.setStretchAllColumns(true);
|
||||||
Table.bringToFront();
|
Table.bringToFront();
|
||||||
|
|
||||||
TableRow tr1 = new TableRow(getContext());
|
|
||||||
addTableText(tr1, "Downloading Teams...");
|
|
||||||
Table.addView(tr1);
|
|
||||||
|
|
||||||
final RequestTask rq = new RequestTask();
|
final RequestTask rq = new RequestTask();
|
||||||
rq.onResult(teamsStr -> {
|
rq.onResult(teamsStr -> {
|
||||||
TableRow tr11 = new TableRow(getContext());
|
|
||||||
addTableText(tr11, "Downloading Matches...");
|
|
||||||
Table.addView(tr11);
|
|
||||||
|
|
||||||
final RequestTask rq1 = new RequestTask();
|
final RequestTask rq1 = new RequestTask();
|
||||||
rq1.onResult(matchesStr -> {
|
rq1.onResult(matchesStr -> {
|
||||||
matchTable(matchesStr, teamsStr, eventData);
|
matchTable(matchesStr, teamsStr, eventData);
|
||||||
stopLoading();
|
AlertManager.stopLoading();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
rq1.execute((TBAAddress + "event/" + matchKey + "/matches"), TBAHeader);
|
rq1.execute((TBAAddress + "event/" + matchKey + "/matches"), TBAHeader);
|
||||||
@@ -104,18 +100,13 @@ public class TBAEventFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addTableText(TableRow tr, String textStr){
|
private void addTableText(TableRow tr, String textStr){
|
||||||
TextView text = new TextView(getContext());
|
tr.addView(new TextViewBuilder(getContext(), textStr)
|
||||||
text.setTextSize(18);
|
.size(18)
|
||||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
// .align_center()
|
||||||
text.setText(textStr);
|
.build());
|
||||||
tr.addView(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void matchTable(String matchesString, String teamsString, JSONObject eventData){
|
public void matchTable(String matchesString, String teamsString, JSONObject eventData){
|
||||||
Table.removeAllViews();
|
|
||||||
Table.setStretchAllColumns(true);
|
|
||||||
Table.bringToFront();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final JSONArray matchData = new JSONArray(matchesString);
|
final JSONArray matchData = new JSONArray(matchesString);
|
||||||
// final JSONArray matchData = new JSONArray();
|
// final JSONArray matchData = new JSONArray();
|
||||||
@@ -130,30 +121,19 @@ public class TBAEventFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Event code at top
|
// Event code at top
|
||||||
TextView tv = new TextView(getContext());
|
Table.addView(new TextViewBuilder(getContext(), matchKey)
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(18)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
tv.setText(matchKey);
|
|
||||||
tv.setTextSize(18);
|
|
||||||
Table.addView(tv);
|
|
||||||
|
|
||||||
// Event Name
|
// Event Name
|
||||||
tv = new TextView(getContext());
|
Table.addView(new TextViewBuilder(getContext(), matchName)
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(28)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText(matchName);
|
|
||||||
tv.setTextSize(28);
|
|
||||||
Table.addView(tv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Save button
|
// Save button
|
||||||
Button btn = new Button(getContext());
|
MaterialButton btn = new MaterialButton(getContext());
|
||||||
btn.setText("Save");
|
btn.setText("Save");
|
||||||
btn.setTextSize(18);
|
btn.setTextSize(18);
|
||||||
btn.setLayoutParams(new TableRow.LayoutParams(
|
btn.setLayoutParams(new TableRow.LayoutParams(
|
||||||
@@ -165,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){
|
if(teamData.length() == 0){
|
||||||
tv = new TextView(getContext());
|
Table.addView(new TextViewBuilder(getContext(), "This event has no teams released yet...")
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(18)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
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);
|
|
||||||
|
|
||||||
btn.setVisibility(View.GONE);
|
btn.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
}else if(matchData.length() == 0){
|
}else if(matchData.length() == 0){
|
||||||
tv = new TextView(getContext());
|
Table.addView(new TextViewBuilder(getContext(), "This event has no matches released yet...")
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(18)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText("This event has no matches released yet...");
|
|
||||||
tv.setTextSize(18);
|
|
||||||
Table.addView(tv);
|
|
||||||
|
|
||||||
tv = new TextView(getContext());
|
Table.addView(new TextViewBuilder(getContext(), "Try manually adding practice matches.")
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
.align_center()
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.size(18)
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.build());
|
||||||
));
|
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
||||||
tv.setText("Try manually adding practice matches.");
|
|
||||||
tv.setTextSize(18);
|
|
||||||
Table.addView(tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tv = new TextView(getContext());
|
Table.addView(
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
new TextViewBuilder(getContext(), "Teams")
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.align_center()
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.size(28)
|
||||||
));
|
.build()
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
);
|
||||||
tv.setText("Teams");
|
|
||||||
tv.setTextSize(28);
|
|
||||||
Table.addView(tv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sort the teams into numerical order
|
||||||
int[] teams = new int[teamData.length()];
|
int[] teams = new int[teamData.length()];
|
||||||
|
|
||||||
for(int i = 0 ; i < teamData.length(); i++){
|
for(int i = 0 ; i < teamData.length(); i++){
|
||||||
@@ -235,28 +189,26 @@ public class TBAEventFragment extends Fragment {
|
|||||||
|
|
||||||
Arrays.sort(teams);
|
Arrays.sort(teams);
|
||||||
|
|
||||||
|
|
||||||
|
// Loop through each match
|
||||||
TableRow tr = null;
|
TableRow tr = null;
|
||||||
for(int i=0; i < teamData.length(); i++){
|
for(int i=0; i < teamData.length(); i++){
|
||||||
// frcTeam team = event.teams.get(i);
|
|
||||||
int num = teams[i];
|
int num = teams[i];
|
||||||
|
|
||||||
|
// If this is every 7th row, add the new row.
|
||||||
if(i % 7 == 0){
|
if(i % 7 == 0){
|
||||||
if(i != 0)
|
if(i != 0)
|
||||||
Table.addView(tr);
|
Table.addView(tr);
|
||||||
tr = new TableRow(getContext());
|
tr = new TableRow(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView text = new TextView(getContext());
|
|
||||||
text.setTextSize(18);
|
|
||||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
|
||||||
|
|
||||||
text.setText(String.valueOf(num));
|
tr.addView(
|
||||||
// if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){
|
new TextViewBuilder(getContext(), String.valueOf(num))
|
||||||
// text.setBackgroundColor(0x3000FF00);
|
.align_center()
|
||||||
// }else{
|
.size(18)
|
||||||
// text.setBackgroundColor(0x30FF0000);
|
.build()
|
||||||
// }
|
);
|
||||||
tr.addView(text);
|
|
||||||
}
|
}
|
||||||
if(tr != null)
|
if(tr != null)
|
||||||
Table.addView(tr);
|
Table.addView(tr);
|
||||||
@@ -269,19 +221,13 @@ public class TBAEventFragment extends Fragment {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
tv = new TextView(getContext());
|
Table.addView(
|
||||||
tv.setLayoutParams(new TableRow.LayoutParams(
|
new TextViewBuilder(getContext(), "Matches")
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
.align_center()
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
.size(28)
|
||||||
));
|
.build()
|
||||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
);
|
||||||
tv.setText("Matches");
|
|
||||||
tv.setTextSize(28);
|
|
||||||
Table.addView(tv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tr = new TableRow(getContext());
|
tr = new TableRow(getContext());
|
||||||
addTableText(tr, "#");
|
addTableText(tr, "#");
|
||||||
addTableText(tr, "Red-1");
|
addTableText(tr, "Red-1");
|
||||||
@@ -335,22 +281,24 @@ public class TBAEventFragment extends Fragment {
|
|||||||
int[] redKeys = new int[3];
|
int[] redKeys = new int[3];
|
||||||
|
|
||||||
for(int b=0;b<6;b++){
|
for(int b=0;b<6;b++){
|
||||||
TextView text = new TextView(getContext());
|
TextViewBuilder text = new TextViewBuilder(getContext())
|
||||||
text.setTextSize(18);
|
.size(18)
|
||||||
text.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); // Text align center
|
.align_center();
|
||||||
tr.addView(text);
|
|
||||||
|
|
||||||
if(b < 3){
|
if(b < 3){
|
||||||
String str = redAlliance.getString(b).substring(3);
|
String str = redAlliance.getString(b).substring(3);
|
||||||
redKeys[b] = Integer.parseInt(str);
|
redKeys[b] = Integer.parseInt(str);
|
||||||
text.setText(str);
|
text.text(str);
|
||||||
text.setBackgroundColor(tba_red);
|
text.tv.setBackgroundColor(tba_red);
|
||||||
}else{
|
}else{
|
||||||
String str = blueAlliance.getString(b-3).substring(3);
|
String str = blueAlliance.getString(b-3).substring(3);
|
||||||
blueKeys[b-3] = Integer.parseInt(str);
|
blueKeys[b-3] = Integer.parseInt(str);
|
||||||
text.setText(str);
|
text.text(str);
|
||||||
text.setBackgroundColor(tba_blue);
|
text.tv.setBackgroundColor(tba_blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tr.addView(text.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
Table.addView(tr);
|
Table.addView(tr);
|
||||||
@@ -365,22 +313,14 @@ public class TBAEventFragment extends Fragment {
|
|||||||
toggle = !toggle;
|
toggle = !toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// btn.setOnClickListener(v -> {
|
|
||||||
// if(saveData(matchesOBJ, teamData, eventData)){
|
|
||||||
// alert("Info", "Saved!");
|
|
||||||
// }else{
|
|
||||||
// alert("Error", "Error saving files.");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
}catch (JSONException j){
|
}catch (JSONException j){
|
||||||
AlertManager.error("Failed Downloading", j);
|
AlertManager.error("Failed Downloading", j);
|
||||||
stopLoading();
|
AlertManager.stopLoading();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean saveData(ArrayList<frcMatch> matchData, JSONArray teamData, JSONObject eventData){
|
private boolean saveData(ArrayList<frcMatch> matchData, JSONArray teamData, JSONObject eventData){
|
||||||
startLoading("Saving data...");
|
AlertManager.startLoading("Downloading team data...");
|
||||||
|
|
||||||
Thread t = new Thread(() -> {
|
Thread t = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
@@ -405,16 +345,44 @@ public class TBAEventFragment extends Fragment {
|
|||||||
teamObj.country = team.getString("country");
|
teamObj.country = team.getString("country");
|
||||||
teamObj.startingYear = team.getInt("rookie_year");
|
teamObj.startingYear = team.getInt("rookie_year");
|
||||||
|
|
||||||
ImageRequestTask imageRequestTask = new ImageRequestTask();
|
|
||||||
|
|
||||||
imageRequestTask.onResult(bitmap -> {
|
RequestTask rq = new RequestTask();
|
||||||
teamObj.bitmap = bitmap;
|
rq.onResult(s -> {
|
||||||
teamObj.teamColor = frcTeam.findPrimaryColor(bitmap);
|
try {
|
||||||
teams.add(teamObj);
|
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;
|
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()) {
|
while (teams.size() != teamData.length()) {
|
||||||
@@ -431,31 +399,15 @@ public class TBAEventFragment extends Fragment {
|
|||||||
AlertManager.toast("Saved!");
|
AlertManager.toast("Saved!");
|
||||||
|
|
||||||
getActivity().runOnUiThread(() -> findNavController(this).navigate(R.id.action_navigation_tba_event_to_navigation_transfer));
|
getActivity().runOnUiThread(() -> findNavController(this).navigate(R.id.action_navigation_tba_event_to_navigation_transfer));
|
||||||
stopLoading();
|
AlertManager.stopLoading();
|
||||||
|
|
||||||
}catch(Exception j) {
|
}catch(Exception j) {
|
||||||
AlertManager.error(j);
|
AlertManager.error(j);
|
||||||
stopLoading();
|
AlertManager.stopLoading();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startLoading(String title){
|
|
||||||
getActivity().runOnUiThread(() -> {
|
|
||||||
if(loadingDialog != null && loadingDialog.isShowing())
|
|
||||||
loadingDialog.dismiss();
|
|
||||||
loadingDialog = ProgressDialog.show(getActivity(), title, "Please wait...");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopLoading(){
|
|
||||||
getActivity().runOnUiThread(() -> {
|
|
||||||
if (loadingDialog != null)
|
|
||||||
loadingDialog.cancel();
|
|
||||||
loadingDialog = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.ridgebotics.ridgescout.ui.views.TBAEventOption;
|
|||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.RequestTask;
|
import com.ridgebotics.ridgescout.utility.RequestTask;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.builders.TextViewBuilder;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -54,12 +55,6 @@ public class TBASelectorFragment extends Fragment {
|
|||||||
|
|
||||||
Table = binding.matchTable;
|
Table = binding.matchTable;
|
||||||
|
|
||||||
Table.setStretchAllColumns(true);
|
|
||||||
|
|
||||||
TableRow tr = new TableRow(getContext());
|
|
||||||
addTableText(tr, "Loading Events...");
|
|
||||||
Table.addView(tr);
|
|
||||||
|
|
||||||
startLoading("Loading Events...");
|
startLoading("Loading Events...");
|
||||||
|
|
||||||
final RequestTask rq = new RequestTask();
|
final RequestTask rq = new RequestTask();
|
||||||
@@ -77,14 +72,6 @@ public class TBASelectorFragment extends Fragment {
|
|||||||
return binding.getRoot();
|
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){
|
public static int getEventTypeWeight(String type){
|
||||||
switch(type){
|
switch(type){
|
||||||
case "Preseason": return -3;
|
case "Preseason": return -3;
|
||||||
@@ -103,7 +90,7 @@ public class TBASelectorFragment extends Fragment {
|
|||||||
public void eventTable(String dataString){
|
public void eventTable(String dataString){
|
||||||
|
|
||||||
Table.removeAllViews();
|
Table.removeAllViews();
|
||||||
Table.setStretchAllColumns(true);
|
// Table.setStretchAllColumns(true);
|
||||||
Table.bringToFront();
|
Table.bringToFront();
|
||||||
|
|
||||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|||||||
@@ -65,13 +65,13 @@ public class TransferFragment extends Fragment {
|
|||||||
|
|
||||||
binding.SyncButton.setOnClickListener(v -> {
|
binding.SyncButton.setOnClickListener(v -> {
|
||||||
binding.SyncButton.setEnabled(false);
|
binding.SyncButton.setEnabled(false);
|
||||||
FTPSync.sync();
|
HttpSync.sync();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(FTPSync.getIsRunning())
|
if(HttpSync.getIsRunning())
|
||||||
binding.SyncButton.setEnabled(false);
|
binding.SyncButton.setEnabled(false);
|
||||||
|
|
||||||
FTPSync.setOnResult((error, upcount, downcount) -> {
|
HttpSync.setOnResult((error, upcount, downcount) -> {
|
||||||
if (getActivity() != null)
|
if (getActivity() != null)
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
binding.SyncButton.setEnabled(true);
|
binding.SyncButton.setEnabled(true);
|
||||||
@@ -79,8 +79,8 @@ public class TransferFragment extends Fragment {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
binding.syncIndicator.setText(FTPSync.text);
|
binding.syncIndicator.setText(HttpSync.text);
|
||||||
FTPSync.setOnUpdateIndicator(text -> {if(getActivity() != null) getActivity().runOnUiThread(() -> binding.syncIndicator.setText(text));});
|
HttpSync.setOnUpdateIndicator(text -> {if(getActivity() != null) getActivity().runOnUiThread(() -> binding.syncIndicator.setText(text));});
|
||||||
|
|
||||||
if(evcode.equals("unset")){
|
if(evcode.equals("unset")){
|
||||||
binding.noEventError.setVisibility(View.VISIBLE);
|
binding.noEventError.setVisibility(View.VISIBLE);
|
||||||
|
|||||||
+2
-1
@@ -8,6 +8,7 @@ import android.bluetooth.BluetoothSocket;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -139,7 +140,7 @@ public class BluetoothReceiver {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (e.getMessage() != null && e.getMessage().contains("bt socket closed, read return: -1")) {
|
if (e.getMessage() != null && e.getMessage().contains("bt socket closed, read return: -1")) {
|
||||||
receiveddata.onConnectionStop();
|
receiveddata.onConnectionStop();
|
||||||
System.out.println("Bluetooth socket closed, treating as end of stream");
|
Log.i(getClass().toString(), "Bluetooth socket closed, treating as end of stream");
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
package com.ridgebotics.ridgescout.ui.transfer.bluetooth;
|
package com.ridgebotics.ridgescout.ui.transfer.bluetooth;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -117,7 +118,7 @@ public class BluetoothReceiverFragment extends Fragment {
|
|||||||
|
|
||||||
private void receiveData(byte[] data, int bytes) {
|
private void receiveData(byte[] data, int bytes) {
|
||||||
byte[] newBytes = FileEditor.getByteBlock(data, 0, bytes);
|
byte[] newBytes = FileEditor.getByteBlock(data, 0, bytes);
|
||||||
System.out.println("Recieved " + bytes + " Bytes over bluetooth!");
|
Log.i(getClass().toString(), "Recieved " + bytes + " Bytes over bluetooth!");
|
||||||
recievedBytes.add(newBytes);
|
recievedBytes.add(newBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ public class BluetoothReceiverFragment extends Fragment {
|
|||||||
ScoutingFile f = ScoutingFile.decode((byte[]) result.get(i).get());
|
ScoutingFile f = ScoutingFile.decode((byte[]) result.get(i).get());
|
||||||
|
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
System.out.println(f.filename);
|
Log.i(getClass().toString(), f.filename);
|
||||||
if (f.write())
|
if (f.write())
|
||||||
result_filenames += f.filename + "\n";
|
result_filenames += f.filename + "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.EncodeHintType;
|
||||||
|
import com.google.zxing.MultiFormatWriter;
|
||||||
|
import com.google.zxing.WriterException;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
|
import com.ridgebotics.ridgescout.utility.TaskRunner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class CodeGenTask implements Callable<List<Bitmap>> {
|
||||||
|
// private Function<List<Bitmap>, String> resultFunction = null;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected List<Bitmap> doInBackground(String... strings) {
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// return new ArrayList<>();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// public void onResult(Function<List<Bitmap>, String> func) {
|
||||||
|
// this.resultFunction = func;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void onPostExecute(List<Bitmap> result) {
|
||||||
|
// super.onPostExecute(result);
|
||||||
|
// if(resultFunction != null){
|
||||||
|
// resultFunction.apply(result);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private final String data;
|
||||||
|
private final int randID;
|
||||||
|
private final int qrSize;
|
||||||
|
private final int qrCount;
|
||||||
|
private final int imageSize;
|
||||||
|
|
||||||
|
public CodeGenTask(String data, int randID, int qrSize, int qrCount, int imageSize) {
|
||||||
|
this.data = data;
|
||||||
|
this.randID = randID;
|
||||||
|
this.qrSize = qrSize;
|
||||||
|
this.qrCount = qrCount;
|
||||||
|
this.imageSize = imageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Bitmap> call() {
|
||||||
|
List<Bitmap> qrBitmaps = new ArrayList<>();
|
||||||
|
|
||||||
|
for(int i=0;i<=((data.length()+1)/qrSize);i++){
|
||||||
|
final int start = i*qrSize;
|
||||||
|
int end = (i+1)*qrSize;
|
||||||
|
if(end >= data.length()){
|
||||||
|
end = data.length();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Bitmap unscaledBitmap = generateQrCode(
|
||||||
|
FileEditor.byteToChar(FileEditor.internalDataVersion, FileEditor.lengthHeaderBytes) +
|
||||||
|
String.valueOf(FileEditor.byteToChar(randID, FileEditor.lengthHeaderBytes)) +
|
||||||
|
FileEditor.byteToChar(i, FileEditor.lengthHeaderBytes) +
|
||||||
|
FileEditor.byteToChar(qrCount - 1, FileEditor.lengthHeaderBytes) +
|
||||||
|
data.substring(start, end)
|
||||||
|
);
|
||||||
|
if(unscaledBitmap == null) {
|
||||||
|
AlertManager.error("Generated image was null!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qrBitmaps.add(Bitmap.createScaledBitmap(unscaledBitmap, imageSize, imageSize, false));
|
||||||
|
// alert("title", ""+(qrCount-1));
|
||||||
|
}catch (WriterException e){
|
||||||
|
AlertManager.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return qrBitmaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap generateQrCode(String contents) throws WriterException {
|
||||||
|
|
||||||
|
final int size = 512;
|
||||||
|
|
||||||
|
if (contents == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
|
||||||
|
|
||||||
|
// The Charset must be UTF-8, Or data will not be transferred properly. IDK why.
|
||||||
|
hints.put(EncodeHintType.CHARACTER_SET, "ISO-8859-1");
|
||||||
|
// hints.put(EncodeHintType.);
|
||||||
|
hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */
|
||||||
|
MultiFormatWriter writer = new MultiFormatWriter();
|
||||||
|
|
||||||
|
BitMatrix result;
|
||||||
|
try {
|
||||||
|
result = writer.encode(contents, BarcodeFormat.DATA_MATRIX, size, size, hints);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// Unsupported format
|
||||||
|
AlertManager.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
int height = result.getHeight();
|
||||||
|
int[] pixels = new int[width * height];
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int offset = y * width;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height,
|
||||||
|
Bitmap.Config.ARGB_8888);
|
||||||
|
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
-107
@@ -1,9 +1,10 @@
|
|||||||
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.CountDownTimer;
|
import android.os.CountDownTimer;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -18,16 +19,11 @@ import androidx.fragment.app.Fragment;
|
|||||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferCodeSenderBinding;
|
import com.ridgebotics.ridgescout.databinding.FragmentTransferCodeSenderBinding;
|
||||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
import com.google.zxing.BarcodeFormat;
|
import com.ridgebotics.ridgescout.utility.TaskRunner;
|
||||||
import com.google.zxing.EncodeHintType;
|
|
||||||
import com.google.zxing.MultiFormatWriter;
|
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumMap;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
// Class to show the code transfer thing.
|
// Class to show the code transfer thing.
|
||||||
@@ -38,23 +34,28 @@ public class CodeGeneratorView extends Fragment {
|
|||||||
private TextView qrIndexN;
|
private TextView qrIndexN;
|
||||||
private TextView qrIndexD;
|
private TextView qrIndexD;
|
||||||
|
|
||||||
private final int maxQrCount = 256; //The max number that can be stored in a byte
|
private static final int maxQrCount = 256; //The max number that can be stored in a byte
|
||||||
|
|
||||||
private final int maxQrSpeed = 5;
|
private static final int maxQrSize = 800;
|
||||||
private final int minQrSpeed = 300 + maxQrSpeed - 1;
|
|
||||||
|
|
||||||
|
private static final int maxQrSpeed = 50;
|
||||||
|
private static final int minQrSpeed = 1000;
|
||||||
|
private static final int defaultQrDelay = 12;
|
||||||
|
|
||||||
|
|
||||||
|
private int imageSize;
|
||||||
|
|
||||||
private int minQrSize = 0;
|
private int minQrSize = 0;
|
||||||
private final int maxQrSize = 800;
|
|
||||||
private int qrSize = 200;
|
private int qrSize = 200;
|
||||||
|
|
||||||
private final int defaultQrDelay = 419;
|
private double qrDelay = 0;
|
||||||
private int qrDelay = 0;
|
|
||||||
private int qrIndex = 0;
|
private int qrIndex = 0;
|
||||||
|
|
||||||
private CountDownTimer timer;
|
private CountDownTimer timer;
|
||||||
private int qrCount = 0;
|
private int qrCount = 0;
|
||||||
|
|
||||||
private ArrayList<Bitmap> qrBitmaps;
|
private List<Bitmap> qrBitmaps = new ArrayList<>();
|
||||||
|
|
||||||
private FragmentTransferCodeSenderBinding binding;
|
private FragmentTransferCodeSenderBinding binding;
|
||||||
|
|
||||||
@@ -77,6 +78,12 @@ public class CodeGeneratorView extends Fragment {
|
|||||||
qrIndexN = binding.qrIndexN;
|
qrIndexN = binding.qrIndexN;
|
||||||
qrIndexD = binding.qrIndexD;
|
qrIndexD = binding.qrIndexD;
|
||||||
|
|
||||||
|
DisplayMetrics displaymetrics = new DisplayMetrics();
|
||||||
|
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
|
||||||
|
// int height = displaymetrics.heightPixels;
|
||||||
|
imageSize = displaymetrics.widthPixels;
|
||||||
|
// = 800;
|
||||||
|
|
||||||
String compressed = new String(FileEditor.blockCompress(data, FileEditor.lengthHeaderBytes), StandardCharsets.ISO_8859_1);
|
String compressed = new String(FileEditor.blockCompress(data, FileEditor.lengthHeaderBytes), StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
if(compressed.isEmpty()){
|
if(compressed.isEmpty()){
|
||||||
@@ -85,75 +92,30 @@ public class CodeGeneratorView extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
minQrSize = Math.round((float)compressed.length() / maxQrCount)+1;
|
minQrSize = Math.round((float)compressed.length() / maxQrCount)+1;
|
||||||
|
qrSize += minQrSize;
|
||||||
qrSizeSlider.setMax(maxQrSize-minQrSize);
|
|
||||||
qrSpeedSlider.setMax((minQrSpeed-maxQrSpeed)*2);
|
|
||||||
|
|
||||||
qrSizeSlider.setProgress(minQrSize+qrSize);
|
|
||||||
qrSpeedSlider.setProgress(defaultQrDelay+5);
|
|
||||||
|
|
||||||
sendData(compressed);
|
sendData(compressed);
|
||||||
|
|
||||||
|
qrSpeedSlider.setMax(maxQrSpeed*2);
|
||||||
|
qrSpeedSlider.setProgress(maxQrSpeed + defaultQrDelay);
|
||||||
|
|
||||||
|
qrSizeSlider.setMax(maxQrSize-minQrSize);
|
||||||
|
qrSizeSlider.setProgress(qrSize-minQrSize);
|
||||||
|
|
||||||
|
startLoop();
|
||||||
|
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Bitmap generateQrCode(String contents) throws WriterException {
|
|
||||||
|
|
||||||
final int size = 512;
|
|
||||||
|
|
||||||
if (contents == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
|
|
||||||
|
|
||||||
// The Charset must be UTF-8, Or data will not be transferred properly. IDK why.
|
|
||||||
hints.put(EncodeHintType.CHARACTER_SET, "ISO-8859-1");
|
|
||||||
// hints.put(EncodeHintType.);
|
|
||||||
hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */
|
|
||||||
MultiFormatWriter writer = new MultiFormatWriter();
|
|
||||||
|
|
||||||
BitMatrix result;
|
|
||||||
try {
|
|
||||||
result = writer.encode(contents, BarcodeFormat.DATA_MATRIX, size, size, hints);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// Unsupported format
|
|
||||||
AlertManager.error(e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int width = result.getWidth();
|
|
||||||
int height = result.getHeight();
|
|
||||||
int[] pixels = new int[width * height];
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
int offset = y * width;
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(width, height,
|
|
||||||
Bitmap.Config.ARGB_8888);
|
|
||||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void sendData(String data){
|
private void sendData(String data){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
qrCount = (data.length()/qrSize)+1;
|
qrCount = (data.length()/qrSize)+1;
|
||||||
qrIndexD.setText(String.valueOf(qrCount));
|
qrIndexD.setText(String.valueOf(qrCount));
|
||||||
|
|
||||||
// alert("size", ""+binding.qrSizeSlider.getProgress()+"\n"+binding.qrSizeSlider.getMax());
|
|
||||||
|
|
||||||
qrSpeedSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
qrSpeedSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
qrDelay = -(minQrSpeed - progress - maxQrSpeed + 1);
|
qrDelay = ((double) progress /maxQrSpeed) - 1;
|
||||||
|
// startLoop();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||||
@@ -173,43 +135,24 @@ public class CodeGeneratorView extends Fragment {
|
|||||||
qrCount = ((data.length()+1)/qrSize) +1;
|
qrCount = ((data.length()+1)/qrSize) +1;
|
||||||
qrIndexD.setText(String.valueOf(qrCount));
|
qrIndexD.setText(String.valueOf(qrCount));
|
||||||
sendData(data);
|
sendData(data);
|
||||||
|
// startLoop();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// qrSizeSlider.setProgress(qr);
|
AlertManager.startLoading("Generating codes...");
|
||||||
|
|
||||||
qrBitmaps = new ArrayList<>();
|
new TaskRunner().executeAsync(new CodeGenTask(data, new Random().nextInt(255), qrSize, qrCount, imageSize), result -> {
|
||||||
|
qrBitmaps = result;
|
||||||
|
AlertManager.stopLoading();
|
||||||
|
qrIndex = 0;
|
||||||
|
});
|
||||||
|
|
||||||
int randID = new Random().nextInt(255);
|
|
||||||
|
|
||||||
for(int i=0;i<=((data.length()+1)/qrSize);i++){
|
|
||||||
final int start = i*qrSize;
|
|
||||||
int end = (i+1)*qrSize;
|
|
||||||
if(end >= data.length()){
|
|
||||||
end = data.length();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// alert("test", ""+Math.ceil((double)data.length()/(double)qrSize));
|
|
||||||
qrBitmaps.add(generateQrCode(
|
|
||||||
FileEditor.byteToChar(FileEditor.internalDataVersion, FileEditor.lengthHeaderBytes) +
|
|
||||||
String.valueOf(FileEditor.byteToChar(randID, FileEditor.lengthHeaderBytes)) +
|
|
||||||
FileEditor.byteToChar(i, FileEditor.lengthHeaderBytes) +
|
|
||||||
FileEditor.byteToChar(qrCount - 1, FileEditor.lengthHeaderBytes) +
|
|
||||||
data.substring(start, end)
|
|
||||||
));
|
|
||||||
// alert("title", ""+(qrCount-1));
|
|
||||||
}catch (WriterException e){
|
|
||||||
AlertManager.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qrIndex = 0;
|
|
||||||
if(timer != null){
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
qrLoop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateQr(){
|
private void updateQr(){
|
||||||
|
if(qrBitmaps.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
qrImage.setImageBitmap(qrBitmaps.get(qrIndex));
|
qrImage.setImageBitmap(qrBitmaps.get(qrIndex));
|
||||||
if(qrDelay > 0) {
|
if(qrDelay > 0) {
|
||||||
this.qrIndex += 1;
|
this.qrIndex += 1;
|
||||||
@@ -226,13 +169,36 @@ public class CodeGeneratorView extends Fragment {
|
|||||||
qrIndexN.setText(String.valueOf(qrIndex+1));
|
qrIndexN.setText(String.valueOf(qrIndex+1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void qrLoop(){
|
private boolean shouldstop = false;
|
||||||
timer = new CountDownTimer(minQrSpeed-Math.abs(qrDelay)+1, 1000) {
|
|
||||||
public void onTick(long millisUntilFinished) {}
|
private void startLoop() {
|
||||||
public void onFinish() {
|
final Handler handler = new Handler();
|
||||||
updateQr();
|
Runnable runnable = new Runnable() {
|
||||||
qrLoop();
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if(shouldstop){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
updateQr();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
AlertManager.error(e);
|
||||||
|
}
|
||||||
|
finally{
|
||||||
|
double a = ((double) maxQrSpeed) / (Math.abs(qrDelay));
|
||||||
|
a = Math.min(Math.max(a, maxQrSpeed), minQrSpeed);
|
||||||
|
handler.postDelayed(this, (long) a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.start();
|
};
|
||||||
|
handler.post(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
shouldstop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class CodeOverlayView extends View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(barColors != null){
|
if(barColors != null){
|
||||||
final double width = getWidth()/barColors.length;
|
final double width = (double) getWidth() /barColors.length;
|
||||||
|
|
||||||
final int top = 0;
|
final int top = 0;
|
||||||
final int bottom = barHeight;
|
final int bottom = barHeight;
|
||||||
|
|||||||
@@ -14,19 +14,69 @@ import com.google.zxing.Reader;
|
|||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
import com.google.zxing.datamatrix.DataMatrixReader;
|
import com.google.zxing.datamatrix.DataMatrixReader;
|
||||||
|
import com.ridgebotics.ridgescout.utility.TaskRunner;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
// Background task for code scanning, to not slow down the scanner.
|
// Background task for code scanning, to not slow down the scanner.
|
||||||
public class CodeScanTask extends AsyncTask<String, String, String>{
|
//public class CodeScanTask extends AsyncTask<String, String, String>{
|
||||||
private Function<String, String> resultFunction = null;
|
// private Function<String, String> resultFunction = null;
|
||||||
|
// private Bitmap image;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected String doInBackground(String... str) {
|
||||||
|
// if(image == null){return null;}
|
||||||
|
//
|
||||||
|
// int width = image.getWidth();
|
||||||
|
// int height = image.getHeight();
|
||||||
|
// int[] pixels = new int[width * height];
|
||||||
|
// image.getPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
|
//
|
||||||
|
// RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
|
||||||
|
// BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||||
|
//
|
||||||
|
// Map<DecodeHintType, Object> hints = new HashMap<>();
|
||||||
|
// hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
|
||||||
|
//// hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
|
||||||
|
// hints.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.of(BarcodeFormat.DATA_MATRIX));
|
||||||
|
//
|
||||||
|
// Reader reader = new DataMatrixReader();
|
||||||
|
// try {
|
||||||
|
// Result result = reader.decode(binaryBitmap, hints);
|
||||||
|
// return result.getText();
|
||||||
|
// } catch (NotFoundException | ChecksumException | FormatException e) {
|
||||||
|
//// AlertManager.error(e);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// public void setImage(Bitmap image){this.image = image;}
|
||||||
|
// public void onResult(Function<String, String> func) {
|
||||||
|
// this.resultFunction = func;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void onPostExecute(String result) {
|
||||||
|
// super.onPostExecute(result);
|
||||||
|
// if(resultFunction != null){
|
||||||
|
// resultFunction.apply(result);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public class CodeScanTask implements Callable<String> {
|
||||||
private Bitmap image;
|
private Bitmap image;
|
||||||
|
|
||||||
|
public CodeScanTask(Bitmap image) {
|
||||||
|
this.image = image;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(String... str) {
|
public String call() {
|
||||||
if(image == null){return null;}
|
if(image == null){return null;}
|
||||||
|
|
||||||
int width = image.getWidth();
|
int width = image.getWidth();
|
||||||
@@ -52,17 +102,4 @@ public class CodeScanTask extends AsyncTask<String, String, String>{
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public void setImage(Bitmap image){this.image = image;}
|
}
|
||||||
public void onResult(Function<String, String> func) {
|
|
||||||
this.resultFunction = func;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(String result) {
|
|
||||||
super.onPostExecute(result);
|
|
||||||
if(resultFunction != null){
|
|
||||||
resultFunction.apply(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+44
-37
@@ -6,6 +6,7 @@ import android.Manifest;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.media.Image;
|
import android.media.Image;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -38,11 +39,15 @@ import com.ridgebotics.ridgescout.utility.AlertManager;
|
|||||||
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
import com.ridgebotics.ridgescout.utility.BuiltByteParser;
|
||||||
import com.ridgebotics.ridgescout.utility.FileEditor;
|
import com.ridgebotics.ridgescout.utility.FileEditor;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.ridgebotics.ridgescout.utility.TaskRunner;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.units.qual.C;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -62,21 +67,12 @@ public class CodeScannerView extends Fragment {
|
|||||||
alert.create().show();
|
alert.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private float scale = 0;
|
|
||||||
private final int downscale = 1;
|
private final int downscale = 1;
|
||||||
private LifecycleOwner lifecycle;
|
private LifecycleOwner lifecycle;
|
||||||
|
|
||||||
private void setImage(Bitmap bmp){
|
private void setImage(Bitmap bmp){
|
||||||
if(scale == 0) {
|
|
||||||
scale = ((float) binding.container.getWidth() / bmp.getWidth()) * ((float) 16 / 9);
|
|
||||||
binding.scannerImage.setTranslationX(0);
|
|
||||||
binding.scannerImage.setTranslationY(0);
|
|
||||||
}
|
|
||||||
scanQRCode(bmp);
|
scanQRCode(bmp);
|
||||||
binding.scannerImage.setImageBitmap(bmp);
|
binding.scannerImage.setImageBitmap(bmp);
|
||||||
binding.scannerThreshold.bringToFront();
|
|
||||||
// alert("test", getChildCount()+"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private Bitmap img
|
// private Bitmap img
|
||||||
@@ -99,37 +95,38 @@ public class CodeScannerView extends Fragment {
|
|||||||
final int height = image.getHeight();
|
final int height = image.getHeight();
|
||||||
|
|
||||||
int[] pixels = new int[width * height];
|
int[] pixels = new int[width * height];
|
||||||
for (int y = 0; y < height; y++) {
|
for (int i = 0; i < width*height; i++) {
|
||||||
for (int x = 0; x < width; x++) {
|
int L = levelMap[yBuffer.get(i) & 0xff];
|
||||||
int L = levelMap[yBuffer.get() & 0xff];
|
pixels[i] = 0xff000000 | (L << 16) | (L << 8) | L;
|
||||||
pixels[y * width + x] = 0xff000000 | (L << 16) | (L << 8) | L;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix matrix = new Matrix();
|
||||||
|
|
||||||
|
matrix.postRotate(90);
|
||||||
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
|
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
|
||||||
|
// Bitmap.rota
|
||||||
|
|
||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
public void scanQRCode(Bitmap bitmap) {
|
public void scanQRCode(Bitmap bitmap) {
|
||||||
|
|
||||||
CodeScanTask async = new CodeScanTask();
|
// CodeScanTask async = new CodeScanTask();
|
||||||
async.setImage(bitmap);
|
new TaskRunner().executeAsync(new CodeScanTask(bitmap), data -> {
|
||||||
async.onResult(data -> {
|
|
||||||
if(data != null){
|
if(data != null){
|
||||||
// alert("test", ""+fileEditor.byteFromChar(data.charAt(0)));
|
// alert("test", ""+fileEditor.byteFromChar(data.charAt(0)));
|
||||||
compileData(
|
compileData(
|
||||||
FileEditor.byteFromChar(data.charAt(0)),
|
FileEditor.byteFromChar(data.charAt(0)),
|
||||||
FileEditor.byteFromChar(data.charAt(1)),
|
FileEditor.byteFromChar(data.charAt(1)),
|
||||||
FileEditor.byteFromChar(data.charAt(2)),
|
FileEditor.byteFromChar(data.charAt(2)),
|
||||||
(FileEditor.byteFromChar(data.charAt(3))+1),
|
(FileEditor.byteFromChar(data.charAt(3))+1),
|
||||||
data.substring(4)
|
data.substring(4)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
async.execute();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// return contents;
|
// return contents;
|
||||||
@@ -231,26 +228,23 @@ public class CodeScannerView extends Fragment {
|
|||||||
|
|
||||||
void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
|
void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
|
||||||
|
|
||||||
Preview preview = new Preview.Builder()
|
Preview preview = new Preview.Builder().build();
|
||||||
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
|
|
||||||
.setTargetRotation(Surface.ROTATION_180)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
CameraSelector cameraSelector = new CameraSelector.Builder()
|
CameraSelector cameraSelector = new CameraSelector.Builder()
|
||||||
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
|
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
|
||||||
|
|
||||||
// .addCameraFilter(CameraFilters.NON)
|
// .addCameraFilter(CameraFilters.NON)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
|
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
|
||||||
// .setTargetResolution(new Size(224, 224))
|
// .setTargetAspectRatio(AspectRatio.RATIO_16_9)
|
||||||
.setOutputImageRotationEnabled(false)
|
|
||||||
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
|
|
||||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||||
|
// .setOutputImageRotationEnabled(true)
|
||||||
|
// .setTargetRotation(Surface.ROTATION_0)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
|
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
|
||||||
@OptIn(markerClass = ExperimentalGetImage.class) @Override
|
@OptIn(markerClass = ExperimentalGetImage.class) @Override
|
||||||
public void analyze(@NonNull ImageProxy image) {
|
public void analyze(@NonNull ImageProxy image) {
|
||||||
@@ -269,6 +263,7 @@ public class CodeScannerView extends Fragment {
|
|||||||
});
|
});
|
||||||
|
|
||||||
cameraProvider.unbindAll();
|
cameraProvider.unbindAll();
|
||||||
|
// cameraProvider.ro
|
||||||
|
|
||||||
cameraProvider.bindToLifecycle(lifecycle,
|
cameraProvider.bindToLifecycle(lifecycle,
|
||||||
cameraSelector, imageAnalysis, preview);
|
cameraSelector, imageAnalysis, preview);
|
||||||
@@ -295,6 +290,7 @@ public class CodeScannerView extends Fragment {
|
|||||||
Log.i("title", ""+qrCount);
|
Log.i("title", ""+qrCount);
|
||||||
barColors = new int[qrCount];
|
barColors = new int[qrCount];
|
||||||
prevQrIndex = qrIndex;
|
prevQrIndex = qrIndex;
|
||||||
|
qrScannedCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean updated;
|
final boolean updated;
|
||||||
@@ -313,8 +309,20 @@ public class CodeScannerView extends Fragment {
|
|||||||
|
|
||||||
if(updated && qrScannedCount >= qrCount){
|
if(updated && qrScannedCount >= qrCount){
|
||||||
|
|
||||||
|
AlertManager.startLoading("Decoding data...");
|
||||||
|
new TaskRunner().executeAsync(new CodeDecodeTask(), result -> {
|
||||||
|
AlertManager.stopLoading();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
prevQrIndex = qrIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CodeDecodeTask implements Callable<Void> {
|
||||||
|
@Override
|
||||||
|
public Void call() {
|
||||||
String compiledString = "";
|
String compiledString = "";
|
||||||
for(int i=0;i<qrCount;i++){
|
for(int i=0;i<qrDataArr.length;i++){
|
||||||
compiledString += qrDataArr[i];
|
compiledString += qrDataArr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,9 +350,8 @@ public class CodeScannerView extends Fragment {
|
|||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
AlertManager.error(e);
|
AlertManager.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
prevQrIndex = qrIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
import com.ridgebotics.ridgescout.types.data.RawDataType;
|
||||||
@@ -208,7 +209,7 @@ public class CandlestickView extends View {
|
|||||||
upperQuartile = DataProcessing.calculatePercentile(teamDataArray, 75);
|
upperQuartile = DataProcessing.calculatePercentile(teamDataArray, 75);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println(locmin + ", " + lowerQuartile + ", " + avg + ", " + upperQuartile + ", " + locmax);
|
Log.i(getClass().toString(), locmin + ", " + lowerQuartile + ", " + avg + ", " + upperQuartile + ", " + locmax);
|
||||||
setData(locmin, lowerQuartile, avg, upperQuartile, locmax, absmin, absmax);
|
setData(locmin, lowerQuartile, avg, upperQuartile, locmax, absmin, absmax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ public class CustomSpinnerView extends LinearLayout {
|
|||||||
this.index = defaultOption;
|
this.index = defaultOption;
|
||||||
|
|
||||||
if(defaultOption != -1)
|
if(defaultOption != -1)
|
||||||
this.item.setText(options.get(defaultOption));
|
this.item.setText("▼ " + options.get(defaultOption));
|
||||||
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||||
@@ -78,7 +78,7 @@ public class CustomSpinnerView extends LinearLayout {
|
|||||||
CustomSpinnerPopup popup = new CustomSpinnerPopup(getContext()).init(options, option -> {
|
CustomSpinnerPopup popup = new CustomSpinnerPopup(getContext()).init(options, option -> {
|
||||||
// dialog.();
|
// dialog.();
|
||||||
if(!isEnabled()) return;
|
if(!isEnabled()) return;
|
||||||
item.setText(option);
|
item.setText("▼ " + option);
|
||||||
index = options.indexOf(option);
|
index = options.indexOf(option);
|
||||||
if(onClickListener != null) {
|
if(onClickListener != null) {
|
||||||
onClickListener.onClick(option, options.indexOf(option));
|
onClickListener.onClick(option, options.indexOf(option));
|
||||||
@@ -105,12 +105,12 @@ public class CustomSpinnerView extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setOption(String option) {
|
public void setOption(String option) {
|
||||||
item.setText(option);
|
item.setText("▼ " + option);
|
||||||
index = options.indexOf(option);
|
index = options.indexOf(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOption(int index) {
|
public void setOption(int index) {
|
||||||
item.setText(options.get(index));
|
item.setText("▼ " + options.get(index));
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
import com.ridgebotics.ridgescout.types.input.FieldposType;
|
||||||
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
|
||||||
// Custom view to display a field position.
|
// Custom view to display a field position.
|
||||||
@@ -24,6 +25,8 @@ public class FieldPosView extends FrameLayout {
|
|||||||
private ImageView imageView;
|
private ImageView imageView;
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
private boolean flip = false;
|
||||||
|
|
||||||
public interface onTapListener {
|
public interface onTapListener {
|
||||||
void onUpdate(int[] pos);
|
void onUpdate(int[] pos);
|
||||||
};
|
};
|
||||||
@@ -65,24 +68,21 @@ public class FieldPosView extends FrameLayout {
|
|||||||
// Set touch listener
|
// Set touch listener
|
||||||
setOnTouchListener((v, event) -> {
|
setOnTouchListener((v, event) -> {
|
||||||
if (enabled && event.getAction() == MotionEvent.ACTION_DOWN) {
|
if (enabled && event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
x = (int) ((event.getX()/getWidth())*255);
|
// If the field image is rotated, rotate the input and output
|
||||||
y = (int) ((event.getY()/getHeight())*255);
|
if(!flip) {
|
||||||
|
x = (int) (event.getX() / getWidth()) * 255;
|
||||||
|
y = (int) (event.getY() / getHeight()) * 255;
|
||||||
|
} else {
|
||||||
|
x = (int) (1 - (event.getX() / getWidth())) * 255;
|
||||||
|
y = (int) (1 - (event.getY() / getHeight())) * 255;
|
||||||
|
}
|
||||||
|
System.out.println("X: " + x + ", Y: " + y);
|
||||||
tl.onUpdate(getPos());
|
tl.onUpdate(getPos());
|
||||||
invalidate();
|
invalidate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
switch(SettingsManager.getFieldImageIndex()){
|
|
||||||
case "2025":
|
|
||||||
setImageResource(R.drawable.field_2025);
|
|
||||||
break;
|
|
||||||
case "2025 (Flipped)":
|
|
||||||
setImageResource(R.drawable.field_2025_flipped);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPos(int[] pos){
|
public void setPos(int[] pos){
|
||||||
@@ -96,10 +96,28 @@ public class FieldPosView extends FrameLayout {
|
|||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
if (x >= 0 && y >= 0) {
|
if (x >= 0 && y >= 0) {
|
||||||
canvas.drawCircle(
|
|
||||||
((float) x /255)*getWidth(),
|
float cx;
|
||||||
((float) y /255)*getHeight(),
|
float cy;
|
||||||
POINT_RADIUS, paint);
|
// If the field image is rotated, rotate the input and output
|
||||||
|
if(!flip) {
|
||||||
|
cx = ((float) x / 255)*getWidth();
|
||||||
|
cy = ((float) y / 255)*getHeight();
|
||||||
|
} else {
|
||||||
|
cx = (1 - (float) x / 255)*getWidth();
|
||||||
|
cy = (1 - (float) y /255)*getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawCircle(cx, cy, POINT_RADIUS, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldImage(FieldposType.FieldImage image) {
|
||||||
|
if(image.flippable && SettingsManager.getFieldImageFlipped()) {
|
||||||
|
setImageResource(image.resId_flipped);
|
||||||
|
flip = true;
|
||||||
|
} else {
|
||||||
|
setImageResource(image.resId_normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package com.ridgebotics.ridgescout.ui.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
|
||||||
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||||
|
|
||||||
|
import org.w3c.dom.Text;
|
||||||
|
|
||||||
|
// A view for displaying information about a team.
|
||||||
|
public class MatchScoutingIndicator extends RelativeLayout {
|
||||||
|
public MatchScoutingIndicator(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MatchScoutingIndicator(Context context) {
|
||||||
|
super(context);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView match_indicator_alliance_pos_text;
|
||||||
|
public TextView match_indicator_bar_team_num;
|
||||||
|
public TextView match_indicator_matchnum;
|
||||||
|
public TextView match_indicator_username;
|
||||||
|
public ImageButton match_indicator_back_button;
|
||||||
|
public ImageButton match_indicator_next_button;
|
||||||
|
private ConstraintLayout box;
|
||||||
|
private View coloredBackground;
|
||||||
|
|
||||||
|
public void init(Context context) {
|
||||||
|
LayoutInflater.from(context).inflate(R.layout.view_match_scouting_indicator, this, true);
|
||||||
|
match_indicator_back_button = findViewById(R.id.match_indicator_back_button);
|
||||||
|
match_indicator_next_button = findViewById(R.id.match_indicator_next_button);
|
||||||
|
match_indicator_alliance_pos_text = findViewById(R.id.match_indicator_alliance_pos_text);
|
||||||
|
match_indicator_username = findViewById(R.id.match_indicator_username);
|
||||||
|
match_indicator_matchnum = findViewById(R.id.match_indicator_matchnum);
|
||||||
|
match_indicator_bar_team_num = findViewById(R.id.match_indicator_bar_team_num);
|
||||||
|
box = findViewById(R.id.file_indicator_box);
|
||||||
|
coloredBackground = findViewById(R.id.match_indicator_background);
|
||||||
|
|
||||||
|
int currentNightMode = getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
switch (currentNightMode) {
|
||||||
|
case Configuration.UI_MODE_NIGHT_NO:
|
||||||
|
// Night mode is not active on device
|
||||||
|
match_indicator_back_button.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
|
||||||
|
match_indicator_next_button.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
|
||||||
|
break;
|
||||||
|
case Configuration.UI_MODE_NIGHT_YES:
|
||||||
|
// Night mode is active on device
|
||||||
|
match_indicator_back_button.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
|
||||||
|
match_indicator_next_button.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username){
|
||||||
|
match_indicator_username.setText(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlliancePos(String alliancePos){
|
||||||
|
match_indicator_alliance_pos_text.setText(alliancePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMatchNum(String matchNum){
|
||||||
|
match_indicator_matchnum.setText(matchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeamNum(String teamNum){
|
||||||
|
match_indicator_bar_team_num.setText(teamNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color){
|
||||||
|
// Set color of main background rectangle
|
||||||
|
Drawable box_drawable = box.getBackground();
|
||||||
|
box_drawable.mutate();
|
||||||
|
box_drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(color,hsv);
|
||||||
|
|
||||||
|
int background_color = Color.HSVToColor(220, new float[]{
|
||||||
|
hsv[0],
|
||||||
|
Math.min(hsv[1], 0.75f),
|
||||||
|
Math.min(hsv[2], 0.5f)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set color of main background rectangle, slightly dimmer
|
||||||
|
coloredBackground.setBackgroundColor(
|
||||||
|
background_color
|
||||||
|
);
|
||||||
|
|
||||||
|
Drawable left_drawable = match_indicator_back_button.getBackground();
|
||||||
|
left_drawable.mutate();
|
||||||
|
left_drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
|
||||||
|
Drawable right_drawable = match_indicator_next_button.getBackground();
|
||||||
|
right_drawable.mutate();
|
||||||
|
right_drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.ridgebotics.ridgescout.R;
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
import com.ridgebotics.ridgescout.types.input.FieldposType;
|
||||||
|
import com.ridgebotics.ridgescout.utility.SettingsManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -48,9 +50,6 @@ public class MultiFieldPosView extends FrameLayout {
|
|||||||
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||||
imageView.setAdjustViewBounds(true);
|
imageView.setAdjustViewBounds(true);
|
||||||
addView(imageView);
|
addView(imageView);
|
||||||
|
|
||||||
setImageResource(R.drawable.field_2025);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPos(int[] pos){
|
public void addPos(int[] pos){
|
||||||
@@ -62,6 +61,14 @@ public class MultiFieldPosView extends FrameLayout {
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFieldImage(FieldposType.FieldImage image) {
|
||||||
|
if(image.flippable && SettingsManager.getFieldImageFlipped()) {
|
||||||
|
setImageResource(image.resId_flipped);
|
||||||
|
} else {
|
||||||
|
setImageResource(image.resId_normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.ridgebotics.ridgescout.ui.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
|
||||||
|
import com.ridgebotics.ridgescout.R;
|
||||||
|
|
||||||
|
// A view for displaying information about a team.
|
||||||
|
public class PitScoutingIndicator extends RelativeLayout {
|
||||||
|
public PitScoutingIndicator(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PitScoutingIndicator(Context context) {
|
||||||
|
super(context);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView pit_indicator_username;
|
||||||
|
public TextView pit_indicator_team_num;
|
||||||
|
private ConstraintLayout box;
|
||||||
|
private View coloredBackground;
|
||||||
|
|
||||||
|
public void init(Context context) {
|
||||||
|
LayoutInflater.from(context).inflate(R.layout.view_pit_scouting_indicator, this, true);
|
||||||
|
pit_indicator_username = findViewById(R.id.pit_indicator_username);
|
||||||
|
pit_indicator_team_num = findViewById(R.id.pit_indicator_teamnum);
|
||||||
|
|
||||||
|
box = findViewById(R.id.pit_indicator_box);
|
||||||
|
coloredBackground = findViewById(R.id.pit_indicator_background);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username){
|
||||||
|
pit_indicator_username.setText(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeamNum(int teamNum) {
|
||||||
|
pit_indicator_team_num.setText(String.valueOf(teamNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color){
|
||||||
|
// Set color of main background rectangle
|
||||||
|
Drawable box_drawable = box.getBackground();
|
||||||
|
box_drawable.mutate();
|
||||||
|
box_drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(color,hsv);
|
||||||
|
|
||||||
|
int background_color = Color.HSVToColor(220, new float[]{
|
||||||
|
hsv[0],
|
||||||
|
Math.min(hsv[1], 0.75f),
|
||||||
|
Math.min(hsv[2], 0.5f)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set color of main background rectangle, slightly dimmer
|
||||||
|
coloredBackground.setBackgroundColor(
|
||||||
|
background_color
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package com.ridgebotics.ridgescout.utility;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -113,4 +114,22 @@ public class AlertManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ProgressDialog loadingDialog;
|
||||||
|
|
||||||
|
public static void startLoading(String title){
|
||||||
|
((Activity) context).runOnUiThread(() -> {
|
||||||
|
if(loadingDialog != null && loadingDialog.isShowing())
|
||||||
|
loadingDialog.dismiss();
|
||||||
|
loadingDialog = ProgressDialog.show(context, title, "Please wait...");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopLoading(){
|
||||||
|
((Activity) context).runOnUiThread(() -> {
|
||||||
|
if (loadingDialog != null)
|
||||||
|
loadingDialog.cancel();
|
||||||
|
loadingDialog = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import android.graphics.Color;
|
|||||||
public class Colors {
|
public class Colors {
|
||||||
// Lists and stuff
|
// Lists and stuff
|
||||||
public static final int color_found = 0x7f00ff00;
|
public static final int color_found = 0x7f00ff00;
|
||||||
public static final int color_rescout = 0x7f0000ff;
|
public static final int color_rescout = 0xff007fff;
|
||||||
public static final int color_not_found = 0x7f7f0000;
|
public static final int color_not_found = 0x7f7f0000;
|
||||||
|
|
||||||
|
|
||||||
@@ -14,9 +14,9 @@ public class Colors {
|
|||||||
public static final int unfocused_background_color = 0x50118811;
|
public static final int unfocused_background_color = 0x50118811;
|
||||||
|
|
||||||
|
|
||||||
public static final int unsaved_color = 0x60ff0000;
|
public static final int unsaved_color = 0xffaa0000;
|
||||||
public static final int saved_color = 0x6000ff00;
|
public static final int saved_color = 0xff00aa00;
|
||||||
public static final int rescout_color = 0x600000ff;
|
public static final int rescout_color = 0xff007fff;
|
||||||
|
|
||||||
|
|
||||||
// Data graphs
|
// Data graphs
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ package com.ridgebotics.ridgescout.utility;
|
|||||||
|
|
||||||
import com.ridgebotics.ridgescout.scoutingData.Fields;
|
import com.ridgebotics.ridgescout.scoutingData.Fields;
|
||||||
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
import com.ridgebotics.ridgescout.scoutingData.transfer.TransferType;
|
||||||
|
import com.ridgebotics.ridgescout.types.ColabArray;
|
||||||
import com.ridgebotics.ridgescout.types.frcEvent;
|
import com.ridgebotics.ridgescout.types.frcEvent;
|
||||||
import com.ridgebotics.ridgescout.types.input.FieldType;
|
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.
|
// Static class to hold loaded data, for ease of access.
|
||||||
public class DataManager {
|
public class DataManager {
|
||||||
public static String evcode;
|
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(){
|
public static void reload_rescout_list(){
|
||||||
if(!FileEditor.fileExist(evcode + ".rescout")) {rescout_list = new ArrayList<>(); return;}
|
String filename = evcode + ".rescout";
|
||||||
byte[] file = FileEditor.readFile(evcode + ".rescout");
|
if(!FileEditor.fileExist(filename)) {rescout_list = new ColabArray(); return;}
|
||||||
if(file == null) {rescout_list = new ArrayList<>(); return;}
|
byte[] file = FileEditor.readFile(filename);
|
||||||
|
if(file == null) {rescout_list = new ColabArray(); return;}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BuiltByteParser bbp = new BuiltByteParser(file);
|
rescout_list = ColabArray.decode(file);
|
||||||
rescout_list = new ArrayList<>(Arrays.asList((String[]) (bbp.parse().get(0).get())));
|
|
||||||
|
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
AlertManager.error("Error loading scout fields", e);
|
AlertManager.error("Error loading rescouting list", e);
|
||||||
rescout_list = new ArrayList<>();
|
rescout_list = new ColabArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save_rescout_list() {
|
public static void save_rescout_list() {
|
||||||
|
String filename = evcode + ".rescout";
|
||||||
try {
|
try {
|
||||||
if(rescout_list.size() == 0){
|
FileEditor.writeFile(filename, rescout_list.encode());
|
||||||
FileEditor.deleteFile(evcode + ".rescout");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuilder bb = new ByteBuilder();
|
|
||||||
bb.addStringArray(rescout_list.toArray(new String[0]));
|
|
||||||
FileEditor.writeFile(evcode + ".rescout", bb.build());
|
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
AlertManager.error("Error saving scout fields", e);
|
AlertManager.error("Error saving rescouting list", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static String scoutNotice = "";
|
public static String scoutNotice = "";
|
||||||
|
|
||||||
public static void reload_scout_notice(){
|
public static void reload_scout_notice(){
|
||||||
@@ -106,7 +105,7 @@ public class DataManager {
|
|||||||
|
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
AlertManager.error("Error loading scout notice", e);
|
AlertManager.error("Error loading scout notice", e);
|
||||||
rescout_list = new ArrayList<>();
|
scoutNotice = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
package com.ridgebotics.ridgescout.utility;
|
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 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.frcEvent;
|
||||||
import com.ridgebotics.ridgescout.types.frcTeam;
|
import com.ridgebotics.ridgescout.types.frcTeam;
|
||||||
|
|
||||||
@@ -15,6 +23,8 @@ import java.io.IOException;
|
|||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -27,18 +37,17 @@ import java.util.zip.Inflater;
|
|||||||
|
|
||||||
// Helper class for binary editing
|
// Helper class for binary editing
|
||||||
public final class FileEditor {
|
public final class FileEditor {
|
||||||
|
@SuppressLint("SdCardPath")
|
||||||
public final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
public final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
||||||
public static final byte internalDataVersion = 0x01;
|
public static final byte internalDataVersion = 0x01;
|
||||||
public static final int maxCompressedBlockSize = 4096;
|
public static final int maxCompressedBlockSize = 4096;
|
||||||
public static final int lengthHeaderBytes = 3;
|
public static final int lengthHeaderBytes = 3;
|
||||||
|
|
||||||
|
|
||||||
public static final String TBAAddress = "https://www.thebluealliance.com/api/v3/";
|
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";
|
public static final String TBAHeader = "X-TBA-Auth-Key: tjEKSZojAU2pgbs2mBt06SKyOakVhLutj3NwuxLTxPKQPLih11aCIwRIVFXKzY4e";
|
||||||
|
|
||||||
// private TimeZone localTimeZone = TimeZone.getDefault();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static String binaryVisualize(byte[] bytes){
|
public static String binaryVisualize(byte[] bytes){
|
||||||
String returnStr = "";
|
String returnStr = "";
|
||||||
@@ -100,7 +109,7 @@ public final class FileEditor {
|
|||||||
|
|
||||||
|
|
||||||
public static int byteFromChar(char c){
|
public static int byteFromChar(char c){
|
||||||
byte[] bytes = (String.valueOf(c)).getBytes(Charset.defaultCharset());
|
byte[] bytes = (String.valueOf(c)).getBytes(StandardCharsets.ISO_8859_1);
|
||||||
return Byte.toUnsignedInt(bytes[0]);
|
return Byte.toUnsignedInt(bytes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,16 +242,19 @@ public final class FileEditor {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean writeFile(String filepath, byte[] data) {
|
public static boolean writeFile(String filepath, byte[] data) {
|
||||||
|
return writeFile(new File(baseDir + filepath), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean writeFile(File file, byte[] data) {
|
||||||
try {
|
try {
|
||||||
FileOutputStream output = new FileOutputStream(baseDir + filepath);
|
FileOutputStream output = new FileOutputStream(file.getPath());
|
||||||
output.write(data);
|
output.write(data);
|
||||||
output.close();
|
output.close();
|
||||||
|
|
||||||
// Date d = new Date();
|
// Date d = new Date();
|
||||||
|
|
||||||
new File(baseDir + filepath).setLastModified(new Date().getTime());
|
file.setLastModified(new Date().getTime());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
@@ -279,10 +291,15 @@ public final class FileEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] readFile(String path){
|
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();
|
int size = (int) file.length();
|
||||||
byte[] bytes = new byte[size];
|
byte[] bytes = new byte[size];
|
||||||
try {
|
try {
|
||||||
@@ -290,9 +307,6 @@ public final class FileEditor {
|
|||||||
buf.read(bytes, 0, bytes.length);
|
buf.read(bytes, 0, bytes.length);
|
||||||
buf.close();
|
buf.close();
|
||||||
return bytes;
|
return bytes;
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
AlertManager.error(e);
|
|
||||||
return null;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
AlertManager.error(e);
|
AlertManager.error(e);
|
||||||
return null;
|
return null;
|
||||||
@@ -314,6 +328,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){
|
public static boolean setEvent(frcEvent event){
|
||||||
@@ -373,34 +410,31 @@ public final class FileEditor {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static String[] getFiles(){
|
||||||
public static String[] getEventFiles(String evcode){
|
|
||||||
File f = new File(baseDir);
|
File f = new File(baseDir);
|
||||||
File[] files = f.listFiles();
|
File[] files = f.listFiles();
|
||||||
|
|
||||||
if(files == null){return new String[0];}
|
if(files == null){return new String[0];}
|
||||||
|
|
||||||
ArrayList<String> outFiles = new ArrayList<>();
|
List<String> outFiles = new ArrayList<>();
|
||||||
outFiles.add("matches.fields");
|
|
||||||
outFiles.add("pits.fields");
|
|
||||||
// outFiles.add(evcode + ".eventdata");
|
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
String name = file.getName();
|
if (!file.isDirectory()) {
|
||||||
if(!file.isDirectory() && name.startsWith(evcode)) {
|
|
||||||
outFiles.add(file.getName());
|
outFiles.add(file.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String[] filenames = outFiles.toArray(new String[0]);
|
String[] filenames = outFiles.toArray(new String[0]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Arrays.sort(filenames, (o1, o2) -> {
|
Arrays.sort(filenames, (o1, o2) -> {
|
||||||
try {
|
try {
|
||||||
if (!o1.contains("-") || !o2.contains("-"))
|
if (!o1.contains("-") || !o2.contains("-"))
|
||||||
return 0;
|
return o2.compareTo(o1);
|
||||||
return Integer.valueOf(o1.split("-")[1]).compareTo(Integer.valueOf(o2.split("-")[1]));
|
return Integer.valueOf(o1.split("-")[1].split("\\.")[0]).compareTo(Integer.valueOf(o2.split("-")[1].split("\\.")[0]));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
AlertManager.error(e);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -412,6 +446,24 @@ public final class FileEditor {
|
|||||||
return filenames;
|
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
|
// 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 {
|
// public static String imageToBitMap(byte[] data) throws IOException {
|
||||||
// Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
// Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
||||||
@@ -424,5 +476,72 @@ public final class FileEditor {
|
|||||||
public static boolean setTeams(Context context, String key, ArrayList<frcTeam> teams){
|
public static boolean setTeams(Context context, String key, ArrayList<frcTeam> teams){
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
package com.ridgebotics.ridgescout.utility;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
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(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) {
|
||||||
|
this.downloadUrl = downloadUrl;
|
||||||
|
this.destinationFile = destinationFile;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected File doInBackground(Void... voids) {
|
||||||
|
return run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public File run() {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
InputStream inputStream = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(downloadUrl);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
// Configure connection for GET request
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.setConnectTimeout(30000); // 30 seconds
|
||||||
|
connection.setReadTimeout(60000); // 60 seconds
|
||||||
|
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
// Check response code
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (responseCode < 200 || responseCode >= 300) {
|
||||||
|
String errorResponse = readErrorResponse(connection);
|
||||||
|
errorMessage = "Download failed. Response code: " + responseCode +
|
||||||
|
(errorResponse != null ? ". Error: " + errorResponse : "");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get file size for progress tracking
|
||||||
|
long fileSize = connection.getContentLengthLong();
|
||||||
|
if (fileSize == -1) {
|
||||||
|
fileSize = connection.getContentLength(); // fallback for older API
|
||||||
|
}
|
||||||
|
|
||||||
|
inputStream = connection.getInputStream();
|
||||||
|
|
||||||
|
// Create destination file and directories if needed
|
||||||
|
if (destinationFile.getParentFile() != null && !destinationFile.getParentFile().exists()) {
|
||||||
|
if (!destinationFile.getParentFile().mkdirs()) {
|
||||||
|
errorMessage = "Failed to create destination directory: " + destinationFile.getParentFile().getAbsolutePath();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
long downloadedBytes = 0;
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
if (isCancelled()) {
|
||||||
|
deletePartialFile();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
downloadedBytes += bytesRead;
|
||||||
|
|
||||||
|
// Update progress if file size is known
|
||||||
|
if (fileSize > 0) {
|
||||||
|
int progress = (int) ((downloadedBytes * 100) / fileSize);
|
||||||
|
publishProgress(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.flush();
|
||||||
|
|
||||||
|
// FileEditor.writeFile(destinationFile, outputStream.toByteArray());
|
||||||
|
// Log.d(TAG, "Download successful. File saved to: " + destinationFile.getAbsolutePath());
|
||||||
|
return destinationFile;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
AlertManager.error(e);
|
||||||
|
errorMessage = "Download error: " + e.getMessage();
|
||||||
|
// Log.e(TAG, errorMessage, e);
|
||||||
|
deletePartialFile();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
closeResources(inputStream, outputStream, connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(File result) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onResult(outputStream, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancelled() {
|
||||||
|
deletePartialFile();
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onResult(null, "Download cancelled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readErrorResponse(HttpURLConnection connection) {
|
||||||
|
try {
|
||||||
|
InputStream errorStream = connection.getErrorStream();
|
||||||
|
if (errorStream != null) {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
response.append(line);
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
return response.toString();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
AlertManager.error("Error reading error response", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deletePartialFile() {
|
||||||
|
if (destinationFile != null && destinationFile.exists()) {
|
||||||
|
if (destinationFile.delete()) {
|
||||||
|
AlertManager.error("Partial download file deleted");
|
||||||
|
} else {
|
||||||
|
AlertManager.error("Failed to delete partial download file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeResources(InputStream inputStream, OutputStream outputStream, HttpURLConnection connection) {
|
||||||
|
try {
|
||||||
|
if (inputStream != null) inputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
AlertManager.error("Error closing input stream", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (outputStream != null) outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
AlertManager.error("Error closing output stream", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
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";
|
||||||
|
|
||||||
|
public interface UploadCallback {
|
||||||
|
void onResult(String error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String uploadUrl;
|
||||||
|
private File fileToUpload;
|
||||||
|
private UploadCallback callback;
|
||||||
|
private String errorMessage;
|
||||||
|
private String[] headers;
|
||||||
|
|
||||||
|
public HttpPutFile(String uploadUrl, File fileToUpload, UploadCallback callback, String[] headers) {
|
||||||
|
this.uploadUrl = uploadUrl;
|
||||||
|
this.fileToUpload = fileToUpload;
|
||||||
|
this.callback = callback;
|
||||||
|
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;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!fileToUpload.exists()) {
|
||||||
|
errorMessage = "File does not exist: " + fileToUpload.getAbsolutePath();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
URL url = new URL(uploadUrl);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
// Configure connection for PUT request
|
||||||
|
connection.setRequestMethod("PUT");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
connection.setRequestProperty("Content-Type", "application/octet-stream");
|
||||||
|
connection.setRequestProperty("Content-Length", String.valueOf(fileToUpload.length()));
|
||||||
|
connection.setConnectTimeout(5000); // 5 seconds
|
||||||
|
connection.setReadTimeout(10000); // 10 seconds
|
||||||
|
|
||||||
|
for(int i = 0; i < headers.length; i++){
|
||||||
|
String[] split = headers[i].split(": ");
|
||||||
|
connection.setRequestProperty(split[0], split[1]);
|
||||||
|
}
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
outputStream = connection.getOutputStream();
|
||||||
|
fileInputStream = new FileInputStream(fileToUpload);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
long totalBytes = fileToUpload.length();
|
||||||
|
long uploadedBytes = 0;
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
|
||||||
|
if (isCancelled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
uploadedBytes += bytesRead;
|
||||||
|
|
||||||
|
// Update progress
|
||||||
|
int progress = (int) ((uploadedBytes * 100) / totalBytes);
|
||||||
|
publishProgress(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.flush();
|
||||||
|
|
||||||
|
// Check response code
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (responseCode >= 200 && responseCode < 300) {
|
||||||
|
// Log.d(TAG, "Upload successful. Response code: " + responseCode);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Read error response if available
|
||||||
|
String errorResponse = readErrorResponse(connection);
|
||||||
|
errorMessage = "Upload failed. Response code: " + responseCode +
|
||||||
|
(errorResponse != null ? ". Error: " + errorResponse : "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
errorMessage = "Upload error: " + e.getMessage();
|
||||||
|
AlertManager.error(errorMessage, e);
|
||||||
|
// Log.e(TAG, errorMessage, e);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
closeResources(fileInputStream, outputStream, connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean success) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onResult(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancelled() {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onResult("Upload cancelled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readErrorResponse(HttpURLConnection connection) {
|
||||||
|
try {
|
||||||
|
InputStream errorStream = connection.getErrorStream();
|
||||||
|
if (errorStream != null) {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
response.append(line);
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
return response.toString();
|
||||||
|
}
|
||||||
|
} catch (IOException 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("Error closing input stream", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (outputStream != null) outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
AlertManager.error("Error closing output stream", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,11 +25,24 @@ public class ImageRequestTask extends AsyncTask<String, Void, Bitmap> {
|
|||||||
try {
|
try {
|
||||||
URL url = new URL(src);
|
URL url = new URL(src);
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
// We do a little bit of spoofing
|
||||||
|
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
|
||||||
connection.setDoInput(true);
|
connection.setDoInput(true);
|
||||||
connection.connect();
|
connection.connect();
|
||||||
InputStream input = connection.getInputStream();
|
|
||||||
return BitmapFactory.decodeStream(input);
|
int code = connection.getResponseCode();
|
||||||
} catch (FileNotFoundException e) {
|
switch (code) {
|
||||||
|
case 200:
|
||||||
|
InputStream input = connection.getInputStream();
|
||||||
|
return BitmapFactory.decodeStream(input);
|
||||||
|
case 403:
|
||||||
|
// AlertManager.error("Got 403, Going to https://www.thebluealliance.com/avatars may fix this");
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
AlertManager.error("Error downloading image " + src, "Got response code: " + code);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e){
|
||||||
return null;
|
return null;
|
||||||
} catch (IOException e){
|
} catch (IOException e){
|
||||||
AlertManager.error("Error downloading image " + src, e);
|
AlertManager.error("Error downloading image " + src, e);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class SettingsManager {
|
|||||||
|
|
||||||
public static final String SelEVCodeKey = "selected_event_code";
|
public static final String SelEVCodeKey = "selected_event_code";
|
||||||
public static final String YearNumKey = "year_num";
|
public static final String YearNumKey = "year_num";
|
||||||
public static final String FieldImageKey = "field_image";
|
public static final String FieldImageKey = "field_image_flipped";
|
||||||
|
|
||||||
public static final String MatchNumKey = "match_num";
|
public static final String MatchNumKey = "match_num";
|
||||||
public static final String AllyPosKey = "alliance_pos";
|
public static final String AllyPosKey = "alliance_pos";
|
||||||
@@ -28,6 +28,7 @@ public class SettingsManager {
|
|||||||
public static final String BtUUIDKey = "bt_uuid";
|
public static final String BtUUIDKey = "bt_uuid";
|
||||||
public static final String FTPEnabled = "ftp_enabled";
|
public static final String FTPEnabled = "ftp_enabled";
|
||||||
public static final String FTPServer = "ftp_server";
|
public static final String FTPServer = "ftp_server";
|
||||||
|
public static final String FTPKey = "ftp_key";
|
||||||
public static final String FTPSendMetaFiles = "ftp_send_meta_files";
|
public static final String FTPSendMetaFiles = "ftp_send_meta_files";
|
||||||
|
|
||||||
public static final String EnableQuickAllianceChangeKey = "enable_quick_alliance_change";
|
public static final String EnableQuickAllianceChangeKey = "enable_quick_alliance_change";
|
||||||
@@ -46,14 +47,15 @@ public class SettingsManager {
|
|||||||
hm.put(SelEVCodeKey, "unset");
|
hm.put(SelEVCodeKey, "unset");
|
||||||
hm.put(WifiModeKey, false);
|
hm.put(WifiModeKey, false);
|
||||||
hm.put(YearNumKey, 2025);
|
hm.put(YearNumKey, 2025);
|
||||||
hm.put(FieldImageKey, "2025");
|
hm.put(FieldImageKey, false);
|
||||||
hm.put(MatchNumKey, 0);
|
hm.put(MatchNumKey, 0);
|
||||||
hm.put(AllyPosKey, "red-1");
|
hm.put(AllyPosKey, "red-1");
|
||||||
hm.put(DataModeKey, 0);
|
hm.put(DataModeKey, 0);
|
||||||
hm.put(TeamsDataModeKey, 0);
|
hm.put(TeamsDataModeKey, 0);
|
||||||
hm.put(BtUUIDKey, UUID.randomUUID().toString());
|
hm.put(BtUUIDKey, UUID.randomUUID().toString());
|
||||||
hm.put(FTPEnabled, false);
|
hm.put(FTPEnabled, false);
|
||||||
hm.put(FTPServer, "0.0.0.0");
|
hm.put(FTPServer, "http://127.0.0.1:8080");
|
||||||
|
hm.put(FTPKey, "5uper_5ecure_k3y");
|
||||||
hm.put(FTPSendMetaFiles, false);
|
hm.put(FTPSendMetaFiles, false);
|
||||||
hm.put(EnableQuickAllianceChangeKey, false);
|
hm.put(EnableQuickAllianceChangeKey, false);
|
||||||
hm.put(CustomEventsKey, false);
|
hm.put(CustomEventsKey, false);
|
||||||
@@ -75,7 +77,7 @@ public class SettingsManager {
|
|||||||
getEditor().putBoolean(WifiModeKey, (boolean) defaults.get( WifiModeKey )).apply();
|
getEditor().putBoolean(WifiModeKey, (boolean) defaults.get( WifiModeKey )).apply();
|
||||||
|
|
||||||
getEditor() .putInt(YearNumKey, (int) defaults.get( YearNumKey )).apply();
|
getEditor() .putInt(YearNumKey, (int) defaults.get( YearNumKey )).apply();
|
||||||
getEditor() .putString(FieldImageKey, (String) defaults.get( FieldImageKey )).apply();
|
getEditor() .putBoolean(FieldImageKey, (boolean) defaults.get( FieldImageKey )).apply();
|
||||||
getEditor() .putInt(MatchNumKey, (int) defaults.get( MatchNumKey )).apply();
|
getEditor() .putInt(MatchNumKey, (int) defaults.get( MatchNumKey )).apply();
|
||||||
getEditor() .putString(AllyPosKey, (String) defaults.get( AllyPosKey )).apply();
|
getEditor() .putString(AllyPosKey, (String) defaults.get( AllyPosKey )).apply();
|
||||||
getEditor() .putInt(DataModeKey, (int) defaults.get( DataModeKey )).apply();
|
getEditor() .putInt(DataModeKey, (int) defaults.get( DataModeKey )).apply();
|
||||||
@@ -106,8 +108,8 @@ public class SettingsManager {
|
|||||||
public static int getYearNum(){return prefs.getInt( YearNumKey, (int) defaults.get(YearNumKey));}
|
public static int getYearNum(){return prefs.getInt( YearNumKey, (int) defaults.get(YearNumKey));}
|
||||||
public static void setYearNum(int num){ getEditor().putInt( YearNumKey,num).apply();}
|
public static void setYearNum(int num){ getEditor().putInt( YearNumKey,num).apply();}
|
||||||
|
|
||||||
public static String getFieldImageIndex(){return prefs.getString( FieldImageKey, (String) defaults.get(FieldImageKey));}
|
public static boolean getFieldImageFlipped(){return prefs.getBoolean(FieldImageKey, (boolean) defaults.get(FieldImageKey));}
|
||||||
public static void setFieldImageIndex(String str){ getEditor().putString( FieldImageKey,str).apply();}
|
public static void setFieldImageFlipped(boolean bool){ getEditor().putBoolean(FieldImageKey, bool).apply();}
|
||||||
|
|
||||||
public static int getMatchNum(){return prefs.getInt( MatchNumKey, (int) defaults.get(MatchNumKey));}
|
public static int getMatchNum(){return prefs.getInt( MatchNumKey, (int) defaults.get(MatchNumKey));}
|
||||||
public static void setMatchNum(int num){ getEditor().putInt( MatchNumKey,num).apply();}
|
public static void setMatchNum(int num){ getEditor().putInt( MatchNumKey,num).apply();}
|
||||||
@@ -131,6 +133,9 @@ public class SettingsManager {
|
|||||||
public static String getFTPServer(){return prefs.getString( FTPServer, (String) defaults.get(FTPServer));}
|
public static String getFTPServer(){return prefs.getString( FTPServer, (String) defaults.get(FTPServer));}
|
||||||
public static void setFTPServer(String str){ getEditor().putString( FTPServer,str).apply();}
|
public static void setFTPServer(String str){ getEditor().putString( FTPServer,str).apply();}
|
||||||
|
|
||||||
|
public static String getFTPKey(){return prefs.getString( FTPKey, (String) defaults.get(FTPKey));}
|
||||||
|
public static void setFTPKey(String str){ getEditor().putString( FTPKey,str).apply();}
|
||||||
|
|
||||||
public static boolean getFTPSendMetaFiles(){return prefs.getBoolean(FTPSendMetaFiles, (boolean) defaults.get(FTPSendMetaFiles));}
|
public static boolean getFTPSendMetaFiles(){return prefs.getBoolean(FTPSendMetaFiles, (boolean) defaults.get(FTPSendMetaFiles));}
|
||||||
public static void setFTPSendMetaFiles(boolean bool){getEditor().putBoolean(FTPSendMetaFiles,bool).apply();}
|
public static void setFTPSendMetaFiles(boolean bool){getEditor().putBoolean(FTPSendMetaFiles,bool).apply();}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.ridgebotics.ridgescout.utility;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/58767733/the-asynctask-api-is-deprecated-in-android-11-what-are-the-alternatives
|
||||||
|
public class TaskRunner {
|
||||||
|
private final Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
public interface Callback<R> {
|
||||||
|
void onComplete(R result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <R> void executeAsync(Callable<R> callable, Callback<R> callback) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
final R result;
|
||||||
|
try {
|
||||||
|
result = callable.call();
|
||||||
|
handler.post(() -> {
|
||||||
|
callback.onComplete(result);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="800dp"
|
||||||
|
android:height="800dp"
|
||||||
|
android:viewportWidth="20"
|
||||||
|
android:viewportHeight="20">
|
||||||
|
<path
|
||||||
|
android:pathData="M14,5v10l-9,-5 9,-5z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="800dp"
|
||||||
|
android:height="800dp"
|
||||||
|
android:viewportWidth="20"
|
||||||
|
android:viewportHeight="20">
|
||||||
|
<path
|
||||||
|
android:pathData="M15,10l-9,5V5l9,5z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</vector>
|
||||||
@@ -29,7 +29,31 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
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
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -92,17 +92,6 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_next_match"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
android:text="TextView"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_name" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_match_alliance"
|
android:id="@+id/text_match_alliance"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -122,6 +111,15 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/event_button" />
|
app:layout_constraintTop_toBottomOf="@+id/event_button" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/info_box"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/text_name" />
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,28 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<com.ridgebotics.ridgescout.ui.views.MatchScoutingIndicator
|
||||||
|
android:id="@+id/bindicator"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
android:id="@+id/scrollView3"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.0">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/MatchScoutArea"
|
android:id="@+id/MatchScoutArea"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingTop="48dp">
|
android:paddingTop="48dp">
|
||||||
|
|
||||||
@@ -25,16 +37,15 @@
|
|||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:background="@drawable/border"
|
android:background="@drawable/border"
|
||||||
android:padding="10dp"
|
android:orientation="horizontal"
|
||||||
android:orientation="horizontal">
|
android:padding="10dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/scouting_notice_text"
|
android:id="@+id/scouting_notice_text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:text="Scouting Notice"
|
||||||
android:text="Scouting Notice">
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"/>
|
||||||
</TextView>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
@@ -46,75 +57,4 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/file_indicator"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="#60ff0000"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/back_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Back"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/next_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Next"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/alliance_pos_text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Temp"
|
|
||||||
android:textAlignment="center"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/matchnum"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/back_button"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/username" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/username"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Temp"
|
|
||||||
android:textAlignment="center"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/matchnum"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/back_button"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/matchnum"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Temp"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/bar_team_num"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Temp"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/next_button"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/matchnum"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -4,54 +4,27 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<com.ridgebotics.ridgescout.ui.views.PitScoutingIndicator
|
||||||
android:id="@+id/pit_file_indicator"
|
android:id="@+id/pit_indicator"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="60dp"
|
||||||
android:background="#60ff0000"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pit_bar_team_num"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="4388"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pitUsername"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Username"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/pit_bar_team_num"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/pitScoutArea"
|
android:id="@+id/pitScoutArea"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingTop="48dp">
|
android:paddingTop="60dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/scouting_notice_box"
|
android:id="@+id/scouting_notice_box"
|
||||||
@@ -60,16 +33,15 @@
|
|||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:background="@drawable/border"
|
android:background="@drawable/border"
|
||||||
android:padding="10dp"
|
android:orientation="horizontal"
|
||||||
android:orientation="horizontal">
|
android:padding="10dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/scouting_notice_text"
|
android:id="@+id/scouting_notice_text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:text="Scouting Notice"
|
||||||
android:text="Scouting Notice">
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"></TextView>
|
||||||
</TextView>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
android:id="@+id/scrollView2"
|
android:id="@+id/scrollView2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="60dp"
|
|
||||||
android:fillViewport="true"
|
android:fillViewport="true"
|
||||||
android:visibility="visible"
|
android:visibility="visible"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
@@ -18,55 +17,70 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<TableLayout
|
<LinearLayout
|
||||||
android:id="@+id/SettingsTable"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
</TableLayout>
|
<TableLayout
|
||||||
|
android:id="@+id/SettingsTable"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <Button-->
|
||||||
|
<!-- android:id="@+id/scoutNoticeButton"-->
|
||||||
|
<!-- android:layout_width="match_parent"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_weight="1"-->
|
||||||
|
<!-- android:layout_margin="5dp"-->
|
||||||
|
<!-- android:text="Edit Scout notice"-->
|
||||||
|
<!-- android:textSize="16sp" />-->
|
||||||
|
|
||||||
|
<!-- <LinearLayout-->
|
||||||
|
<!-- android:layout_width="match_parent"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:orientation="horizontal">-->
|
||||||
|
|
||||||
|
<!-- <Button-->
|
||||||
|
<!-- android:id="@+id/fieldsPitsButton"-->
|
||||||
|
<!-- android:layout_width="match_parent"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_weight="1"-->
|
||||||
|
<!-- android:layout_margin="5dp"-->
|
||||||
|
<!-- android:text="Edit PIT Fields"-->
|
||||||
|
<!-- android:textSize="16sp" />-->
|
||||||
|
|
||||||
|
<!-- <Button-->
|
||||||
|
<!-- android:id="@+id/fieldsMatchesButton"-->
|
||||||
|
<!-- android:layout_width="match_parent"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_weight="1"-->
|
||||||
|
<!-- android:layout_margin="5dp"-->
|
||||||
|
<!-- android:text="Edit MATCH Fields"-->
|
||||||
|
<!-- android:textSize="16sp" />-->
|
||||||
|
|
||||||
|
<!-- </LinearLayout>-->
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<!-- <LinearLayout-->
|
||||||
android:id="@+id/fieldsButton"
|
<!-- android:id="@+id/fieldsButtons"-->
|
||||||
android:layout_width="wrap_content"
|
<!-- android:layout_width="match_parent"-->
|
||||||
android:layout_height="wrap_content"
|
<!-- android:layout_height="wrap_content"-->
|
||||||
android:text="Fields"
|
<!-- android:layout_marginTop="1dp"-->
|
||||||
android:textSize="34sp"
|
<!-- android:gravity="center"-->
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/scrollView2"
|
<!-- android:orientation="horizontal"-->
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
<!-- android:visibility="gone"-->
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||||
|
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||||
|
<!-- app:layout_constraintBottom_toTopOf="@+id/fieldsButton"-->
|
||||||
|
<!-- tools:visibility="visible">-->
|
||||||
|
|
||||||
<LinearLayout
|
<!-- </LinearLayout>-->
|
||||||
android:id="@+id/fieldsButtons"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/fieldsButton"
|
|
||||||
tools:visibility="visible">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/fieldsPitsButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="5dp"
|
|
||||||
android:text="Pits"
|
|
||||||
android:textSize="34sp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/fieldsMatchesButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="5dp"
|
|
||||||
android:text="Matches"
|
|
||||||
android:textSize="34sp" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -14,8 +14,7 @@
|
|||||||
android:id="@+id/teams"
|
android:id="@+id/teams"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical" />
|
||||||
android:paddingTop="48dp" />
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -7,77 +7,65 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/scannerColors"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginTop="15dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/scannerThreshold"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/scannerColors" />
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/scannerBrightness"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/scannerThreshold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/scannerColorsLabel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginBottom="-12dp"
|
|
||||||
android:text="Posterize"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/scannerColors"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/scannerThresholdLabel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginBottom="-12dp"
|
|
||||||
android:text="Exposure"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/scannerThreshold"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/scannerBrightnessLabel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginBottom="-12dp"
|
|
||||||
android:text="Brightness"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/scannerBrightness"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/scannerImage"
|
android:id="@+id/scannerImage"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:rotation="90"
|
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:scaleX="1"
|
|
||||||
android:scaleY="1"
|
|
||||||
android:translationY="-40dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:context=".CodeScannerView" />
|
tools:context=".CodeScannerView" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="3dp"
|
||||||
|
android:padding="3dp"
|
||||||
|
android:background="@drawable/border"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
tools:layout_editor_absoluteX="3dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scannerColorsLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Posterize"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"/>
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/scannerColors"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginTop="15dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scannerThresholdLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Exposure"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"/>
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/scannerThreshold"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scannerBrightnessLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Brightness"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"/>
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/scannerBrightness"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,31 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/qrSizeSlider"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginBottom="60dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/qrImage" />
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/qrSpeedSlider"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginBottom="60dp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/qrSizeSlider"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.971"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/qrImage"
|
|
||||||
app:layout_constraintVertical_bias="0.93" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/qrImage"
|
android:id="@+id/qrImage"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -36,23 +15,48 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/qrSpeedText"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_margin="3dp"
|
||||||
android:text="QR Speed"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/qrSpeedSlider"
|
android:background="@drawable/border"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/qrSizeText"
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/qrSpeedText"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_height="wrap_content"
|
||||||
android:text="QR Size"
|
android:layout_marginStart="8dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/qrSizeSlider"
|
android:text="QR Speed"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/qrSpeedSlider" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/qrSpeedSlider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/qrSizeText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="QR Size"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6" />
|
||||||
|
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/qrSizeSlider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
tools:layout_editor_absoluteY="135dp" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/qrIndexN"
|
android:id="@+id/qrIndexN"
|
||||||
@@ -60,7 +64,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="0"
|
android:text="0"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/qrIndexSlash"
|
app:layout_constraintEnd_toStartOf="@+id/qrIndexSlash"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/qrImage" />
|
app:layout_constraintTop_toBottomOf="@+id/qrImage"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/qrIndexSlash"
|
android:id="@+id/qrIndexSlash"
|
||||||
@@ -69,7 +74,8 @@
|
|||||||
android:text="/"
|
android:text="/"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/qrImage" />
|
app:layout_constraintTop_toBottomOf="@+id/qrImage"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/qrIndexD"
|
android:id="@+id/qrIndexD"
|
||||||
@@ -77,6 +83,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="0"
|
android:text="0"
|
||||||
app:layout_constraintStart_toEndOf="@+id/qrIndexSlash"
|
app:layout_constraintStart_toEndOf="@+id/qrIndexSlash"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/qrImage" />
|
app:layout_constraintTop_toBottomOf="@+id/qrImage"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -8,9 +8,12 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="3dp"
|
android:layout_marginLeft="3dp"
|
||||||
android:orientation="horizontal"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="3dp"
|
||||||
|
android:layout_marginBottom="3dp"
|
||||||
android:background="@drawable/border"
|
android:background="@drawable/border"
|
||||||
|
android:orientation="horizontal"
|
||||||
tools:ignore="UselessParent">
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -18,8 +21,9 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:textSize="24sp"
|
android:overlapAnchor="false"
|
||||||
android:overlapAnchor="false"/>
|
android:text="▼ Options"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -28,9 +32,9 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="9dp"
|
android:layout_marginStart="9dp"
|
||||||
android:layout_marginTop="-5dp"
|
android:layout_marginTop="-6dp"
|
||||||
android:paddingLeft="3dp"
|
android:paddingLeft="3dp"
|
||||||
android:paddingRight="3dp"
|
android:paddingRight="3dp"
|
||||||
android:text="Test"
|
android:text="Test"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"/>
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/file_indicator_box"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:background="@drawable/border"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/match_indicator_background"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/match_indicator_back_button"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:contentDescription="Back"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/triangle_left"
|
||||||
|
android:text="Back"
|
||||||
|
android:background="@drawable/border"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/match_indicator_next_button"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:contentDescription="Next"
|
||||||
|
android:src="@drawable/triangle_right"
|
||||||
|
android:text="Next"
|
||||||
|
android:background="@drawable/border"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/match_indicator_alliance_pos_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="58dp"
|
||||||
|
android:text="Temp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/match_indicator_next_button"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/match_indicator_username"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="58dp"
|
||||||
|
android:text="Temp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/match_indicator_matchnum"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Temp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/match_indicator_bar_team_num"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="3dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Temp"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/match_indicator_matchnum"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/match_indicator_matchnum"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</RelativeLayout>
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/pit_indicator_box"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:background="@drawable/border"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/pit_indicator_background"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pit_indicator_username"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="58dp"
|
||||||
|
android:text="Username"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pit_indicator_teamnum"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:text="4388"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</RelativeLayout>
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
android:text="0"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:textSize="24sp" />
|
android:textSize="24sp" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
android:id="@+id/team_option_logo"
|
android:id="@+id/team_option_logo"
|
||||||
android:layout_width="54dp"
|
android:layout_width="54dp"
|
||||||
android:layout_height="54dp"
|
android:layout_height="54dp"
|
||||||
android:layout_margin="3dp"
|
android:layout_margin="2dp"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintDimensionRatio="1:1"
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.8.0"
|
agp = "8.13.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.1.5"
|
junitVersion = "1.1.5"
|
||||||
espressoCore = "3.5.1"
|
espressoCore = "3.5.1"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#Sun Mar 24 10:48:55 MDT 2024
|
#Sun Mar 24 10:48:55 MDT 2024
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
from ast import mod
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import hashlib
|
||||||
|
from datetime import datetime
|
||||||
|
from bottle import Bottle, run, get, put, static_file, response, request,HTTPResponse
|
||||||
|
from random import SystemRandom
|
||||||
|
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
app = Bottle()
|
||||||
|
|
||||||
|
file_metadata = {}
|
||||||
|
|
||||||
|
def save_metadata():
|
||||||
|
global file_metadata
|
||||||
|
write(METADATA_PATH4, json.dumps(file_metadata))
|
||||||
|
|
||||||
|
def load_metadata():
|
||||||
|
global file_metadata
|
||||||
|
data = read(METADATA_PATH4)
|
||||||
|
if data is not None:
|
||||||
|
file_metadata = json.loads(data)
|
||||||
|
|
||||||
|
api_key = None
|
||||||
|
cryptogen = SystemRandom()
|
||||||
|
|
||||||
|
def aquire_key():
|
||||||
|
global api_key
|
||||||
|
global cryptogen
|
||||||
|
|
||||||
|
if api_key is None:
|
||||||
|
try:
|
||||||
|
api_key = read(API_KEY_PATH).decode("utf-8").strip()
|
||||||
|
except:
|
||||||
|
ran = cryptogen.randrange(10**80)
|
||||||
|
api_key = "%064x" % ran
|
||||||
|
write(API_KEY_PATH, api_key)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def list_html():
|
||||||
|
global file_metadata
|
||||||
|
load_metadata()
|
||||||
|
|
||||||
|
content = '<html><body><table><tr>'
|
||||||
|
for heading in ['File', 'Size', 'Modified', 'Sha256']:
|
||||||
|
content += f'<th>{heading}</th>'
|
||||||
|
content += "</tr>"
|
||||||
|
|
||||||
|
print(file_metadata)
|
||||||
|
|
||||||
|
for filename in file_metadata.keys():
|
||||||
|
content += "<tr>"
|
||||||
|
content += f'<td><a href="/api/{filename}">{filename}</a></td>'
|
||||||
|
content += f'<td>{file_metadata[filename]["size"]}B</td>'
|
||||||
|
content += f'<td>{file_metadata[filename]["modified"]}</td>'
|
||||||
|
content += f'<td>{file_metadata[filename]["sha256"]}</td>'
|
||||||
|
content += "</tr>"
|
||||||
|
|
||||||
|
content += '</table></body></html>'
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/metadata')
|
||||||
|
def metadata():
|
||||||
|
global file_metadata
|
||||||
|
load_metadata()
|
||||||
|
response.content_type = 'application/json'
|
||||||
|
return json.dumps(file_metadata)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/<filename>', method='PUT')
|
||||||
|
def upload(filename):
|
||||||
|
global api_key
|
||||||
|
try:
|
||||||
|
sentkey = request.headers[API_KEY_HEADER]
|
||||||
|
if sentkey != api_key:
|
||||||
|
return HTTPResponse(status=403, body=f"Invalid Key")
|
||||||
|
except:
|
||||||
|
return HTTPResponse(status=403, body="You must specify an 'api_key' header")
|
||||||
|
|
||||||
|
|
||||||
|
global file_metadata
|
||||||
|
load_metadata()
|
||||||
|
|
||||||
|
data = request.body.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
modified = request.headers[MODIFIED_HEADER]
|
||||||
|
except:
|
||||||
|
modified = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
|
||||||
|
|
||||||
|
sha256_hash = hashlib.sha256()
|
||||||
|
sha256_hash.update(data)
|
||||||
|
|
||||||
|
file_metadata[filename] = {
|
||||||
|
'size': len(data),
|
||||||
|
'modified': modified,
|
||||||
|
'sha256': sha256_hash.hexdigest()
|
||||||
|
}
|
||||||
|
|
||||||
|
save_metadata()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
write(os.path.join(DATA_ROOT, filename), data)
|
||||||
|
# save_metadata()
|
||||||
|
# response.content_type = 'application/json'
|
||||||
|
# return json.dumps(file_metadata)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/<filename>')
|
||||||
|
def download(filename):
|
||||||
|
|
||||||
|
data = read(os.path.join(DATA_ROOT, filename))
|
||||||
|
|
||||||
|
if data is not None:
|
||||||
|
response.content_type = 'application/octet-stream'
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
HTTPResponse(status=404, body="File not found")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
mkdir(DATA_ROOT)
|
||||||
|
aquire_key()
|
||||||
|
app.run(host='0.0.0.0', port=8080)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bottle
|
||||||
|
random
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
ROOT = os.path.dirname(__file__)
|
||||||
|
DATA_ROOT = os.path.join(os.path.dirname(__file__), 'server_data')
|
||||||
|
|
||||||
|
METADATA_PATH4 = os.path.join(ROOT, 'metadata.json')
|
||||||
|
API_KEY_PATH = os.path.join(ROOT, 'api_key.txt')
|
||||||
|
|
||||||
|
MODIFIED_HEADER = 'modified'
|
||||||
|
API_KEY_HEADER = 'api_key'
|
||||||
|
|
||||||
|
def mkdir(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
|
||||||
|
def ls(path):
|
||||||
|
try:
|
||||||
|
return os.listdir(path)
|
||||||
|
except:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def read(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
return f.read()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading file {path}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def write(path, data):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
with open(path, mode='ab'): pass
|
||||||
|
|
||||||
|
if isinstance(data, str):
|
||||||
|
data = str.encode(data)
|
||||||
|
|
||||||
|
with open(path, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
Reference in New Issue
Block a user